ref #2380: improve implementation of Dto for use in taxonnavigator
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / ClassificationServiceImpl.java
index 73df05b25d7ca0f63f429fb498ab9137bd6af22c..9de05cfb176b61c0770fefc6d907e0ff2d8d9a63 100644 (file)
@@ -1,4 +1,3 @@
-// $Id$
 /**
 * Copyright (C) 2007 EDIT
 * European Distributed Institute of Taxonomy
@@ -16,6 +15,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -43,19 +43,21 @@ import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
 import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
+import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
 import eu.etaxonomy.cdm.model.common.ITreeNode;
 import eu.etaxonomy.cdm.model.common.MarkerType;
+import eu.etaxonomy.cdm.model.common.TreeIndex;
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
 import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.media.Media;
 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
 import eu.etaxonomy.cdm.model.media.MediaUtils;
-import eu.etaxonomy.cdm.model.name.NonViralName;
+import eu.etaxonomy.cdm.model.name.INonViralName;
 import eu.etaxonomy.cdm.model.name.Rank;
-import eu.etaxonomy.cdm.model.name.TaxonNameBase;
+import eu.etaxonomy.cdm.model.name.TaxonName;
 import eu.etaxonomy.cdm.model.reference.Reference;
 import eu.etaxonomy.cdm.model.taxon.Classification;
 import eu.etaxonomy.cdm.model.taxon.ITaxonNodeComparator;
@@ -154,13 +156,17 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
     }
 
     private void addChildTaxa(TaxonNode originalParentNode, TaxonNode cloneParentNode, Classification classification, TaxonRelationshipType relationshipType){
+        Reference reference = classification.getReference();
        Taxon cloneTaxon = (Taxon) HibernateProxyHelper.deproxy(originalParentNode.getTaxon(), Taxon.class).clone();
-       Reference reference = classification.getReference();
+       cloneTaxon.setSec(reference);
                String microReference = null;
                List<TaxonNode> originalChildNodes = originalParentNode.getChildNodes();
+               HHH_9751_Util.removeAllNull(originalChildNodes);
 
                //add relation between taxa
-               cloneTaxon.addTaxonRelation(originalParentNode.getTaxon(), relationshipType, reference, microReference);
+               if (relationshipType != null){
+                   cloneTaxon.addTaxonRelation(originalParentNode.getTaxon(), relationshipType, reference, microReference);
+               }
 
                TaxonNode cloneChildNode = null;
        //add taxon node to either parent node or classification (no parent node)
@@ -235,6 +241,9 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
     public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, Rank baseRank, List<String> propertyPaths){
 
         TaxonNode thisNode = taxonNodeDao.load(taxonNode.getUuid(), propertyPaths);
+        if(baseRank != null){
+            baseRank = (Rank) termDao.load(baseRank.getUuid());
+        }
         List<TaxonNode> pathToRoot = new ArrayList<TaxonNode>();
         pathToRoot.add(thisNode);
 
@@ -473,12 +482,6 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
 
     }
 
-    @Override
-    public Map<UUID, List<MediaRepresentation>> getAllMediaForChildNodes(Taxon taxon, Classification taxTree, List<String> propertyPaths, int size, int height, int widthOrDuration, String[] mimeTypes){
-        TaxonNode node = taxTree.getNode(taxon);
-
-        return getAllMediaForChildNodes(node, propertyPaths, size, height, widthOrDuration, mimeTypes);
-    }
 
     @Override
     @Transactional(readOnly = false)
@@ -500,11 +503,11 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
        if(allNodesOfClassification == null || allNodesOfClassification.isEmpty()){
                return null;
        }
-       Map<String, List<TaxonNode>> sortedGenusMap = new HashMap<String, List<TaxonNode>>();
+       Map<String, List<TaxonNode>> sortedGenusMap = new HashMap<>();
        for(TaxonNode node:allNodesOfClassification){
                final TaxonNode tn = node;
                Taxon taxon = node.getTaxon();
-               NonViralName name = CdmBase.deproxy(taxon.getName(), NonViralName.class);
+               INonViralName name = taxon.getName();
                String genusOrUninomial = name.getGenusOrUninomial();
                //if rank unknown split string and take first word
                if(genusOrUninomial == null){
@@ -542,7 +545,7 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
      * @param configurator to change certain settings, if null then standard settings will be taken
      * @return new classification with parentNodes for each entry in the map
      */
-    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @SuppressWarnings({ "unchecked" })
        @Transactional(readOnly = false)
        @Override
     public UpdateResult createHierarchyInClassification(Classification classification, CreateHierarchyForClassificationConfigurator configurator){
@@ -551,7 +554,7 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
        Map<String, List<TaxonNode>> map = getSortedGenusList(classification.getAllNodes());
 
        final String APPENDIX = "repaired";
-       String titleCache = org.apache.commons.lang.StringUtils.isBlank(classification.getTitleCache()) ? " " : classification.getTitleCache() ;
+       String titleCache = StringUtils.isBlank(classification.getTitleCache()) ? " " : classification.getTitleCache() ;
        //TODO classification clone???
        Classification newClassification = Classification.NewInstance(titleCache +" "+ APPENDIX);
        newClassification.setReference(classification.getReference());
@@ -564,9 +567,8 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
                for(TaxonNode tNode:listOfTaxonNodes){
                        //take that taxonNode as parent and remove from list with all it possible children
                        //FIXME NPE for name
-                       TaxonNameBase name = tNode.getTaxon().getName();
-                               NonViralName nonViralName = CdmBase.deproxy(name, NonViralName.class);
-                       if(nonViralName.getNameCache().equalsIgnoreCase(genus)){
+                       TaxonName name = tNode.getTaxon().getName();
+                       if(name.getNameCache().equalsIgnoreCase(genus)){
                                TaxonNode clone = (TaxonNode) tNode.clone();
                                if(!tNode.hasChildNodes()){
                                        //FIXME remove classification
@@ -595,10 +597,9 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
                if(parentNode == null){
                        //if no match found in list, create parentNode
                        NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
-                       NonViralName nonViralName = parser.parseFullName(genus);
-                       TaxonNameBase taxonNameBase = nonViralName;
+                       TaxonName TaxonName = (TaxonName)parser.parseFullName(genus);
                        //TODO Sec via configurator
-                       Taxon taxon = Taxon.NewInstance(taxonNameBase, null);
+                       Taxon taxon = Taxon.NewInstance(TaxonName, null);
                        parentNode = newClassification.addChildTaxon(taxon, 0, null, null);
                        result.addUpdatedObject(parentNode);
                }
@@ -672,6 +673,7 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
 
 
     @Override
+    @Transactional
     public DeleteResult delete(UUID classificationUuid, TaxonDeletionConfigurator config){
         DeleteResult result = new DeleteResult();
         Classification classification = dao.findByUuid(classificationUuid);
@@ -682,11 +684,15 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         }
         if (!classification.hasChildNodes()){
             dao.delete(classification);
+            result.addDeletedObject(classification);
+            return result;
         }
-        if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE) ){
+        if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)){
             TaxonNode root = classification.getRootNode();
-            taxonNodeDao.delete(root, true);
+            result.includeResult(taxonNodeService.deleteTaxonNode(root, config));
             dao.delete(classification);
+            result.addDeletedObject(classification);
+
         }
 
 
@@ -698,20 +704,21 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         List<GroupedTaxonDTO> result = new ArrayList<>();
 
         //get treeindex for each taxonUUID
-        Map<UUID, String> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
+        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
 
         //build treeindex list (or tree)
-        List<String> treeIndexClosure = new ArrayList<>();
-        for (String treeIndex : taxonIdTreeIndexMap.values()){
-            String[] splits = treeIndex.substring(1).split(ITreeNode.separator);
+        //TODO make it work with TreeIndex or move there
+        List<String> treeIndexClosureStr = new ArrayList<>();
+        for (TreeIndex treeIndex : taxonIdTreeIndexMap.values()){
+            String[] splits = treeIndex.toString().substring(1).split(ITreeNode.separator);
             String currentIndex = ITreeNode.separator;
             for (String split : splits){
                 if (split.equals("")){
                     continue;
                 }
                 currentIndex += split + ITreeNode.separator;
-                if (!treeIndexClosure.contains(currentIndex) && !split.startsWith(ITreeNode.treePrefix)){
-                    treeIndexClosure.add(currentIndex);
+                if (!treeIndexClosureStr.contains(currentIndex) && !split.startsWith(ITreeNode.treePrefix)){
+                    treeIndexClosureStr.add(currentIndex);
                 }
             }
         }
@@ -719,15 +726,17 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         //get rank sortindex for all parent taxa with sortindex <= minRank and sortIndex >= maxRank (if available)
         Integer minRankOrderIndex = minRank == null ? null : minRank.getOrderIndex();
         Integer maxRankOrderIndex = maxRank == null ? null : maxRank.getOrderIndex();
-        Map<String, Integer> treeIndexSortIndexMapTmp = taxonNodeDao.rankOrderIndexForTreeIndex(treeIndexClosure, minRankOrderIndex, maxRankOrderIndex);
+        List<TreeIndex> treeIndexClosure = TreeIndex.NewListInstance(treeIndexClosureStr);
+
+        Map<TreeIndex, Integer> treeIndexSortIndexMapTmp = taxonNodeDao.rankOrderIndexForTreeIndex(treeIndexClosure, minRankOrderIndex, maxRankOrderIndex);
 
         //remove all treeindex with "exists child in above map(and child.sortindex > xxx)
-        List<String> treeIndexList = new ArrayList<>(treeIndexSortIndexMapTmp.keySet());
-        Collections.sort(treeIndexList, new TreeIndexComparator());
-        Map<String, Integer> treeIndexSortIndexMap = new HashMap<>();
-        String lastTreeIndex = null;
-        for (String treeIndex : treeIndexList){
-            if (lastTreeIndex != null && treeIndex.startsWith(lastTreeIndex)){
+        List<TreeIndex> treeIndexList = TreeIndex.sort(treeIndexSortIndexMapTmp.keySet());
+
+        Map<TreeIndex, Integer> treeIndexSortIndexMap = new HashMap<>();
+        TreeIndex lastTreeIndex = null;
+        for (TreeIndex treeIndex : treeIndexList){
+            if (lastTreeIndex != null && lastTreeIndex.hasChild(treeIndex)){
                 treeIndexSortIndexMap.remove(lastTreeIndex);
             }
             treeIndexSortIndexMap.put(treeIndex, treeIndexSortIndexMapTmp.get(treeIndex));
@@ -735,23 +744,25 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         }
 
         //get taxonID for treeIndexes
-        Map<String, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(treeIndexSortIndexMap.keySet());
+        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(treeIndexSortIndexMap.keySet());
 
         //fill result list
         for (UUID originalTaxonUuid : originalTaxonUuids){
             GroupedTaxonDTO item = new GroupedTaxonDTO();
             result.add(item);
             item.setTaxonUuid(originalTaxonUuid);
-            String groupIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
-            while (groupIndex != null){
-                if (treeIndexTaxonIdMap.get(groupIndex) != null){
-                    UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupIndex);
+            TreeIndex groupTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
+            String groupIndexX = TreeIndex.toString(groupTreeIndex);
+            while (groupTreeIndex != null){
+                if (treeIndexTaxonIdMap.get(groupTreeIndex) != null){
+                    UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
                     item.setGroupTaxonUuid(uuidAndLabel.getUuid());
                     item.setGroupTaxonName(uuidAndLabel.getTitleCache());
                     break;
                 }else{
-                    int index = groupIndex.substring(0, groupIndex.length()-1).lastIndexOf(ITreeNode.separator);
-                    groupIndex = index<0 ? null : groupIndex.substring(0, index+1);
+                    groupTreeIndex = groupTreeIndex.parent();
+//                    int index = groupIndex.substring(0, groupIndex.length()-1).lastIndexOf(ITreeNode.separator);
+//                    groupIndex = index < 0 ? null : groupIndex.substring(0, index+1);
                 }
             }
         }
@@ -759,6 +770,47 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         return result;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<GroupedTaxonDTO> groupTaxaByMarkedParents(List<UUID> originalTaxonUuids, UUID classificationUuid,
+            MarkerType markerType, Boolean flag) {
+
+        List<GroupedTaxonDTO> result = new ArrayList<>();
+
+        //get treeindex for each taxonUUID
+        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
+
+        //get all marked tree indexes
+        Set<TreeIndex> markedTreeIndexes = dao.getMarkedTreeIndexes(markerType, flag);
+
+
+        Map<TreeIndex, TreeIndex> groupedMap = TreeIndex.group(markedTreeIndexes, taxonIdTreeIndexMap.values());
+        Set<TreeIndex> notNullGroups = new HashSet<>(groupedMap.values());
+        notNullGroups.remove(null);
+
+        //get taxonInfo for treeIndexes
+        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(notNullGroups);
+
+        //fill result list
+        for (UUID originalTaxonUuid : originalTaxonUuids){
+            GroupedTaxonDTO item = new GroupedTaxonDTO();
+            result.add(item);
+            item.setTaxonUuid(originalTaxonUuid);
+
+            TreeIndex toBeGroupedTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
+            TreeIndex groupTreeIndex = groupedMap.get(toBeGroupedTreeIndex);
+            UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
+            if (uuidAndLabel != null){
+                item.setGroupTaxonUuid(uuidAndLabel.getUuid());
+                item.setGroupTaxonName(uuidAndLabel.getTitleCache());
+            }
+        }
+
+        return result;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -787,10 +839,7 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         if (taxonBase.isInstanceOf(Synonym.class)){
             isSynonym = true;
             Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
-            Set<Taxon> acceptedTaxa = synonym.getAcceptedTaxa();
-            //we expect every synonym to have only 1 accepted taxon as this is how
-            //CDM will be modelled soon
-            acceptedTaxon = acceptedTaxa.isEmpty()? null : acceptedTaxa.iterator().next();
+            acceptedTaxon = synonym.getAcceptedTaxon();
             if (acceptedTaxon == null) {
                 throw new EntityNotFoundException("Accepted taxon not found for synonym"  );
             }
@@ -812,6 +861,18 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
             throw new EntityNotFoundException("Taxon not found in classficiation with uuid " + classificationUuid + ". Either classification does not exist or does not contain taxon/synonym with uuid " + taxonBaseUuid );
         }
         result.setTaxonNodeUuid(taxonNodeUuid);
+
+        //TODO make it a dao call
+        Taxon parentTaxon = getParentTaxon(classificationUuid, acceptedTaxon);
+        if (parentTaxon != null){
+            result.setParentTaxonUuid(parentTaxon.getUuid());
+            result.setParentTaxonLabel(parentTaxon.getTitleCache());
+            if (parentTaxon.getName() != null){
+                result.setParentNameLabel(parentTaxon.getName().getTitleCache());
+            }
+        }
+
+
         result.setTaxonUuid(taxonBaseUuid);
         result.setClassificationUuid(classificationUuid);
         if (taxonBase.getSec() != null){
@@ -820,29 +881,25 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         }
         result.setTaxonLabel(taxonBase.getTitleCache());
 
-        TaxonNameBase<?,?> name = taxonBase.getName();
+        TaxonName name = taxonBase.getName();
         result.setNameUuid(name.getUuid());
         result.setNameLabel(name.getTitleCache());
-        if (name.isInstanceOf(NonViralName.class)){
-            NonViralName<?> nvn = CdmBase.deproxy(name, NonViralName.class);
-
-            result.setNameWithoutAuthor(nvn.getNameCache());
-            result.setGenusOrUninomial(nvn.getGenusOrUninomial());
-            result.setInfraGenericEpithet(nvn.getInfraGenericEpithet());
-            result.setSpeciesEpithet(nvn.getSpecificEpithet());
-            result.setInfraSpecificEpithet(nvn.getInfraSpecificEpithet());
-
-            result.setAuthorship(nvn.getAuthorshipCache());
-
-            Rank rank = name.getRank();
-            if (rank != null){
-                result.setRankUuid(rank.getUuid());
-                String rankLabel = rank.getAbbreviation();
-                if (StringUtils.isBlank(rankLabel)){
-                    rankLabel = rank.getLabel();
-                }
-                result.setRankLabel(rankLabel);
+        result.setNameWithoutAuthor(name.getNameCache());
+        result.setGenusOrUninomial(name.getGenusOrUninomial());
+        result.setInfraGenericEpithet(name.getInfraGenericEpithet());
+        result.setSpeciesEpithet(name.getSpecificEpithet());
+        result.setInfraSpecificEpithet(name.getInfraSpecificEpithet());
+
+        result.setAuthorship(name.getAuthorshipCache());
+
+        Rank rank = name.getRank();
+        if (rank != null){
+            result.setRankUuid(rank.getUuid());
+            String rankLabel = rank.getAbbreviation();
+            if (StringUtils.isBlank(rankLabel)){
+                rankLabel = rank.getLabel();
             }
+            result.setRankLabel(rankLabel);
         }
 
         boolean recursive = false;
@@ -886,6 +943,27 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         return result;
     }
 
+    /**
+     * @param classificationUuid
+     * @param acceptedTaxon
+     * @return
+     */
+    private Taxon getParentTaxon(UUID classificationUuid, Taxon acceptedTaxon) {
+        if (classificationUuid == null){
+            return null;
+        }
+        TaxonNode parent = null;
+        for (TaxonNode node : acceptedTaxon.getTaxonNodes()){
+            if (classificationUuid.equals(node.getClassification().getUuid())){
+                parent = node.getParent();
+            }
+        }
+        if (parent != null){
+            return parent.getTaxon();
+        }
+        return null;
+    }
+
     /**
      * @param result
      * @param markerTypes
@@ -906,4 +984,5 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         }
     }
 
+
 }