ref #7674 Create default taxon description when adding specimens
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DescriptiveDataSetService.java
index e780b8f6b83c3d5f6816de72f5667c7eda142fcc..d5d97989b0d5a880a80ba96347ea6ee292617b3b 100644 (file)
@@ -8,8 +8,10 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
+import java.util.stream.Collectors;
 
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -17,12 +19,15 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import eu.etaxonomy.cdm.api.service.dto.RowWrapperDTO;
+import eu.etaxonomy.cdm.api.service.dto.SpecimenRowWrapperDTO;
+import eu.etaxonomy.cdm.api.service.dto.TaxonRowWrapperDTO;
 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
 import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
 import eu.etaxonomy.cdm.common.monitor.RemotingProgressMonitorThread;
 import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
 import eu.etaxonomy.cdm.model.common.Language;
+import eu.etaxonomy.cdm.model.common.MarkerType;
 import eu.etaxonomy.cdm.model.description.CategoricalData;
 import eu.etaxonomy.cdm.model.description.DescriptionBase;
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
@@ -32,13 +37,14 @@ import eu.etaxonomy.cdm.model.description.Feature;
 import eu.etaxonomy.cdm.model.description.QuantitativeData;
 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
 import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
+import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.description.TextData;
 import eu.etaxonomy.cdm.model.location.NamedArea;
 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
+import eu.etaxonomy.cdm.model.taxon.Classification;
 import eu.etaxonomy.cdm.model.taxon.Taxon;
-import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
 import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
@@ -56,6 +62,9 @@ public class DescriptiveDataSetService
     @Autowired
     private IOccurrenceService occurrenceService;
 
+    @Autowired
+    private ITaxonService taxonService;
+
     @Autowired
     private IDescriptionService descriptionService;
 
@@ -113,7 +122,16 @@ public class DescriptiveDataSetService
             if(monitor.isCanceled()){
                 return new ArrayList<>();
             }
-            wrappers.add(createRowWrapper(null, description, null, descriptiveDataSet));
+            RowWrapperDTO rowWrapper = null;
+            if(HibernateProxyHelper.isInstanceOf(description, TaxonDescription.class)){
+                rowWrapper = createTaxonRowWrapper(HibernateProxyHelper.deproxy(description, TaxonDescription.class), descriptiveDataSet);
+            }
+            else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
+                rowWrapper = createSpecimenRowWrapper(HibernateProxyHelper.deproxy(description, SpecimenDescription.class), descriptiveDataSet, false);
+            }
+            if(rowWrapper!=null){
+                wrappers.add(rowWrapper);
+            }
             monitor.worked(1);
         }
            return wrappers;
@@ -121,69 +139,112 @@ public class DescriptiveDataSetService
 
     @Override
     public Collection<SpecimenNodeWrapper> loadSpecimens(DescriptiveDataSet descriptiveDataSet){
-        //set filter parameters
+        List<UUID> filteredNodes = findFilteredTaxonNodes(descriptiveDataSet);
+        return occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(filteredNodes, null, null);
+    }
+
+    @Override
+    public List<UUID> findFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet){
         TaxonNodeFilter filter = TaxonNodeFilter.NewRankInstance(descriptiveDataSet.getMinRank(), descriptiveDataSet.getMaxRank());
         descriptiveDataSet.getGeoFilter().forEach(area -> filter.orArea(area.getUuid()));
         descriptiveDataSet.getTaxonSubtreeFilter().forEach(node -> filter.orSubtree(node));
         filter.setIncludeUnpublished(true);
 
-        List<UUID> filteredNodes = taxonNodeService.uuidList(filter);
-        return occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(filteredNodes, null, null);
+        return taxonNodeService.uuidList(filter);
     }
 
     @Override
-    public RowWrapperDTO createRowWrapper(DescriptionBase description, DescriptiveDataSet descriptiveDataSet){
-        return createRowWrapper(null, description, null, descriptiveDataSet);
+    public List<TaxonNode> loadFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet, List<String> propertyPaths){
+        return taxonNodeService.load(findFilteredTaxonNodes(descriptiveDataSet), propertyPaths);
+    }
+
+    private TaxonNode findTaxonNodeForDescription(TaxonNode taxonNode, SpecimenOrObservationBase specimen){
+        Collection<SpecimenNodeWrapper> nodeWrapper = occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(Arrays.asList(taxonNode.getUuid()), null, null);
+        for (SpecimenNodeWrapper specimenNodeWrapper : nodeWrapper) {
+            if(specimenNodeWrapper.getUuidAndTitleCache().getId().equals(specimen.getId())){
+                return taxonNode;
+            }
+        }
+        return null;
     }
 
     @Override
-    public RowWrapperDTO createRowWrapper(SpecimenOrObservationBase specimen, DescriptiveDataSet descriptiveDataSet){
-        return createRowWrapper(specimen, null, null, descriptiveDataSet);
+    public TaxonRowWrapperDTO createTaxonRowWrapper(TaxonDescription description,
+            DescriptiveDataSet descriptiveDataSet) {
+        TaxonNode taxonNode = null;
+        Classification classification = null;
+        Optional<TaxonNode> first = descriptiveDataSet.getTaxonSubtreeFilter().stream()
+                .filter(node->node.getClassification()!=null).findFirst();
+        Optional<Classification> classificationOptional = first.map(node->node.getClassification());
+        if(classificationOptional.isPresent()){
+            classification = classificationOptional.get();
+            Taxon taxon = (Taxon) taxonService.load(description.getTaxon().getId(), Arrays.asList("taxonNodes", "taxonNodes.classification"));
+            taxonNode = taxon.getTaxonNode(classification);
+        }
+        return new TaxonRowWrapperDTO(description, taxonNode);
     }
 
-       private RowWrapperDTO createRowWrapper(SpecimenOrObservationBase specimen, DescriptionBase description, TaxonNode taxonNode, DescriptiveDataSet descriptiveDataSet){
-           if(description!=null){
-               specimen = description.getDescribedSpecimenOrObservation();
-           }
+    @Override
+    public SpecimenRowWrapperDTO createSpecimenRowWrapper(SpecimenDescription description, DescriptiveDataSet descriptiveDataSet,
+            boolean createDefaultTaxonDescription){
+           SpecimenOrObservationBase specimen = description.getDescribedSpecimenOrObservation();
+           TaxonNode taxonNode = null;
         FieldUnit fieldUnit = null;
         String identifier = null;
         NamedArea country = null;
         //supplemental information
-        if(specimen!=null){
-            if(taxonNode==null){
-                Collection<TaxonBase<?>> associatedTaxa = occurrenceService.listAssociatedTaxa(specimen, null, null, null,
-                        Arrays.asList(new String[]{
-                                "taxonNodes",
-                                "taxonNodes.classification",
-                        }));
-                if(associatedTaxa!=null && !associatedTaxa.isEmpty()){
-                    //FIXME: what about multiple associated taxa
-                    Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
-                    if(taxonSubtreeFilter!=null && !taxonSubtreeFilter.isEmpty()){
-                        Taxon taxon = HibernateProxyHelper.deproxy(associatedTaxa.iterator().next(), Taxon.class);
-                        taxonNode = taxon.getTaxonNode(taxonSubtreeFilter.iterator().next().getClassification());
-                    }
-                }
-            }
-            Collection<FieldUnit> fieldUnits = occurrenceService.findFieldUnits(specimen.getUuid(),
-                    Arrays.asList(new String[]{
-                            "gatheringEvent",
-                            "gatheringEvent.country"
-                            }));
-            if(fieldUnits.size()!=1){
-                logger.error("More than one or no field unit found for specimen"); //$NON-NLS-1$
+        //get taxon node
+        Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
+        for (TaxonNode node : taxonSubtreeFilter) {
+            //check for node
+            node = taxonNodeService.load(node.getId(), Arrays.asList("taxon"));
+            taxonNode = findTaxonNodeForDescription(node, specimen);
+            if(taxonNode!=null){
+                break;
             }
             else{
-                fieldUnit = fieldUnits.iterator().next();
-            }
-            if(specimen instanceof DerivedUnit){
-                identifier = occurrenceService.getMostSignificantIdentifier(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
-            }
-            if(fieldUnit!=null && fieldUnit.getGatheringEvent()!=null){
-                country = fieldUnit.getGatheringEvent().getCountry();
+                //check for child nodes
+                List<TaxonNode> allChildren = taxonNodeService.loadChildNodesOfTaxonNode(node, Arrays.asList("taxon"), true, true, null);
+                for (TaxonNode child : allChildren) {
+                    taxonNode = findTaxonNodeForDescription(child, specimen);
+                    if(taxonNode!=null){
+                        break;
+                    }
+                }
             }
         }
-        return new RowWrapperDTO(description, specimen, taxonNode, fieldUnit, identifier, country);
+        if(taxonNode==null){
+            return null;
+        }
+        //taxon node was found
+
+        //get field unit
+        Collection<FieldUnit> fieldUnits = occurrenceService.findFieldUnits(specimen.getUuid(),
+                Arrays.asList(new String[]{
+                        "gatheringEvent",
+                        "gatheringEvent.country"
+                }));
+        if(fieldUnits.size()!=1){
+            logger.error("More than one or no field unit found for specimen"); //$NON-NLS-1$
+            return null;
+        }
+        else{
+            fieldUnit = fieldUnits.iterator().next();
+        }
+        //get identifier
+        if(specimen instanceof DerivedUnit){
+            identifier = occurrenceService.getMostSignificantIdentifier(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
+        }
+        //get country
+        if(fieldUnit!=null && fieldUnit.getGatheringEvent()!=null){
+            country = fieldUnit.getGatheringEvent().getCountry();
+        }
+        //get default taxon description
+        TaxonDescription defaultTaxonDescription = findDefaultTaxonDescription(descriptiveDataSet.getUuid(),
+                taxonNode.getUuid(), createDefaultTaxonDescription);
+        TaxonRowWrapperDTO taxonRowWrapper = defaultTaxonDescription != null
+                ? createTaxonRowWrapper(defaultTaxonDescription, descriptiveDataSet) : null;
+        return new SpecimenRowWrapperDTO(description, taxonNode, fieldUnit, identifier, country, taxonRowWrapper);
        }
 
     @Override
@@ -197,7 +258,41 @@ public class DescriptiveDataSetService
     }
 
     @Override
-    public SpecimenDescription findDescriptionForDescriptiveDataSet(UUID descriptiveDataSetUuid, UUID specimenUuid){
+    public TaxonDescription findDefaultTaxonDescription(UUID descriptiveDataSetUuid, UUID taxonNodeUuid, boolean create){
+        DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
+        TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid, Arrays.asList("taxon", "taxon.descriptions", "taxon.descriptions.markers"));
+        Set<DescriptionBase> dataSetDescriptions = dataSet.getDescriptions();
+        //filter out COMPUTED descriptions
+        List<TaxonDescription> nonComputedDescriptions = taxonNode.getTaxon().getDescriptions().stream()
+                .filter(desc -> desc.getMarkers().stream()
+                        .anyMatch(marker -> marker.getMarkerType().equals(MarkerType.COMPUTED())))
+                .collect(Collectors.toList());
+        for (TaxonDescription taxonDescription : nonComputedDescriptions) {
+            for (DescriptionBase description : dataSetDescriptions) {
+                if(description.getUuid().equals(taxonDescription.getUuid())){
+                    return taxonDescription;
+                }
+            }
+        }
+        if(!create){
+            return null;
+        }
+        //description not yet added to dataset -> create a new one
+        TaxonDescription newTaxonDescription = TaxonDescription.NewInstance(taxonNode.getTaxon());
+        newTaxonDescription.setTitleCache("Dataset "+dataSet.getLabel()+": "+newTaxonDescription.generateTitle(), true); //$NON-NLS-2$
+        dataSet.getDescriptiveSystem().getDistinctFeatures().forEach(wsFeature->{
+            if(wsFeature.isSupportsCategoricalData()){
+                newTaxonDescription.addElement(CategoricalData.NewInstance(wsFeature));
+            }
+            else if(wsFeature.isSupportsQuantitativeData()){
+                newTaxonDescription.addElement(QuantitativeData.NewInstance(wsFeature));
+            }
+        });
+        return newTaxonDescription;
+    }
+
+    @Override
+    public SpecimenDescription findSpecimenDescription(UUID descriptiveDataSetUuid, UUID specimenUuid){
         DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
         SpecimenOrObservationBase specimen = occurrenceService.load(specimenUuid);