Merge branch 'release/5.3.0'
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / ClassificationServiceImpl.java
index 547ea40902073751c79ba90a3ff97be0bda3da3b..726f0b11320917853fe245e5017a119ff93f8a6b 100644 (file)
@@ -1,4 +1,3 @@
-// $Id$
 /**
 * Copyright (C) 2007 EDIT
 * European Distributed Institute of Taxonomy
 package eu.etaxonomy.cdm.api.service;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 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;
 import java.util.TreeMap;
 import java.util.UUID;
 
+import javax.persistence.EntityNotFoundException;
+
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import eu.etaxonomy.cdm.api.service.config.CreateHierarchyForClassificationConfigurator;
+import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;
+import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
+import eu.etaxonomy.cdm.api.service.dto.EntityDTO;
+import eu.etaxonomy.cdm.api.service.dto.GroupedTaxonDTO;
+import eu.etaxonomy.cdm.api.service.dto.MarkedEntityDTO;
+import eu.etaxonomy.cdm.api.service.dto.TaxonInContextDTO;
 import eu.etaxonomy.cdm.api.service.pager.Pager;
 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.exception.FilterException;
+import eu.etaxonomy.cdm.exception.UnpublishedException;
+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;
 import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
+import eu.etaxonomy.cdm.model.taxon.Synonym;
 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.model.taxon.TaxonRelationshipType;
+import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
 import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
 import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;
 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
 import eu.etaxonomy.cdm.persistence.dto.ClassificationLookupDTO;
+import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
+import eu.etaxonomy.cdm.persistence.dto.TaxonStatus;
 import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
 import eu.etaxonomy.cdm.persistence.query.OrderHint;
 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
@@ -58,12 +84,13 @@ import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
 
 /**
  * @author n.hoffmann
- * @created Sep 21, 2009
+ * @since Sep 21, 2009
  */
 @Service
 @Transactional(readOnly = true)
-public class ClassificationServiceImpl extends IdentifiableServiceBase<Classification, IClassificationDao>
-    implements IClassificationService {
+public class ClassificationServiceImpl
+             extends IdentifiableServiceBase<Classification, IClassificationDao>
+             implements IClassificationService {
     private static final Logger logger = Logger.getLogger(ClassificationServiceImpl.class);
 
     @Autowired
@@ -72,6 +99,12 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
     @Autowired
     private ITaxonDao taxonDao;
 
+    @Autowired
+    private ITaxonNodeService taxonNodeService;
+
+    @Autowired
+    private IDefinedTermDao termDao;
+
     @Autowired
     private IBeanInitializer defaultBeanInitializer;
 
@@ -96,29 +129,86 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         return loadTaxonNode(node.getUuid(), propertyPaths);
     }
 
+    public TaxonNode loadTaxonNode(UUID taxonNodeUuid, List<String> propertyPaths){
+        return taxonNodeDao.load(taxonNodeUuid, propertyPaths);
+    }
+
     @Override
-    @Deprecated // use loadTaxonNode(UUID, List<String>) instead
-    public TaxonNode loadTaxonNode(TaxonNode taxonNode, List<String> propertyPaths){
-        return taxonNodeDao.load(taxonNode.getUuid(), propertyPaths);
+    @Transactional(readOnly = false)
+    public UpdateResult cloneClassification(UUID classificationUuid,
+               String name, Reference sec, TaxonRelationshipType relationshipType) {
+        UpdateResult result = new UpdateResult();
+       Classification classification = load(classificationUuid);
+       Classification clone = Classification.NewInstance(name);
+       clone.setReference(sec);
+
+       //clone taxa and taxon nodes
+       List<TaxonNode> childNodes = classification.getRootNode().getChildNodes();
+       for (TaxonNode taxonNode : childNodes) {
+               addChildTaxa(taxonNode, null, clone, relationshipType);
+       }
+       dao.saveOrUpdate(clone);
+       result.setCdmEntity(clone);
+       return result;
     }
 
-    public TaxonNode loadTaxonNode(UUID taxonNodeUuid, List<String> propertyPaths){
-        return taxonNodeDao.load(taxonNodeUuid, propertyPaths);
+    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();
+       cloneTaxon.setSec(reference);
+               String microReference = null;
+               List<TaxonNode> originalChildNodes = originalParentNode.getChildNodes();
+               HHH_9751_Util.removeAllNull(originalChildNodes);
+
+               //add relation between taxa
+               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)
+       if(cloneParentNode==null){
+               cloneChildNode = classification.addChildTaxon(cloneTaxon, reference, microReference);
+       }
+       else{
+               cloneChildNode = cloneParentNode.addChildTaxon(cloneTaxon, reference, microReference);
+       }
+       taxonNodeDao.saveOrUpdate(cloneChildNode);
+       //add children
+               for (TaxonNode originalChildNode : originalChildNodes) {
+               addChildTaxa(originalChildNode, cloneChildNode, classification, relationshipType);
+       }
     }
 
     @Override
-    public List<TaxonNode> listRankSpecificRootNodes(Classification classification, Rank rank, Integer pageSize,
-            Integer pageIndex, List<String> propertyPaths) {
-        return pageRankSpecificRootNodes(classification, rank, pageSize, pageIndex, propertyPaths).getRecords();
+    public List<TaxonNode> listRankSpecificRootNodes(Classification classification, Rank rank,
+            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
+        return listRankSpecificRootNodes(classification, null, rank, includeUnpublished, pageSize, pageIndex, propertyPaths);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, Rank rank, Integer pageSize,
-            Integer pageIndex, List<String> propertyPaths) {
-        long[] numberOfResults = dao.countRankSpecificRootNodes(classification, rank);
+    public List<TaxonNode> listRankSpecificRootNodes(Classification classification,
+            TaxonNode subtree, Rank rank,
+            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
+        return pageRankSpecificRootNodes(classification, subtree, rank, includeUnpublished, pageSize, pageIndex, propertyPaths).getRecords();
+    }
+
+    @Override
+    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, Rank rank,
+            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
+        return pageRankSpecificRootNodes(classification, null, rank, includeUnpublished, pageSize, pageIndex, propertyPaths);
+    }
+
+    @Override
+    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, TaxonNode subtree, Rank rank,
+            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
+        long[] numberOfResults = dao.countRankSpecificRootNodes(classification, subtree, includeUnpublished, rank);
         long totalNumberOfResults = numberOfResults[0] + (numberOfResults.length > 1 ? numberOfResults[1] : 0);
 
-        List<TaxonNode> results = new ArrayList<TaxonNode>();
+        List<TaxonNode> results = new ArrayList<>();
 
         if (AbstractPagerImpl.hasResultsInRange(totalNumberOfResults, pageIndex, pageSize)) { // no point checking again
             Integer limit = PagerUtils.limitFor(pageSize);
@@ -134,7 +224,9 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
                     continue;
                 }
 
-                List<TaxonNode> perQueryResults = dao.listRankSpecificRootNodes(classification, rank, remainingLimit, start, propertyPaths, queryIndex);
+                List<TaxonNode> perQueryResults = dao.listRankSpecificRootNodes(classification,
+                        subtree, rank, includeUnpublished, remainingLimit,
+                        start, propertyPaths, queryIndex);
                 results.addAll(perQueryResults);
                 if(remainingLimit != null ){
                     remainingLimit = remainingLimit - results.size();
@@ -150,44 +242,61 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
 //        long start_t = System.currentTimeMillis();
         Collections.sort(results, taxonNodeComparator); // TODO is ordering during the hibernate query in the dao possible?
 //        System.err.println("service.pageRankSpecificRootNodes() - Collections.sort(results,  taxonNodeComparator) " + (System.currentTimeMillis() - start_t));
-        return new DefaultPagerImpl<TaxonNode>(pageIndex, (int) totalNumberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageIndex, totalNumberOfResults, pageSize, results);
+
+    }
 
+    @Override
+    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, Rank baseRank,
+            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
+        return loadTreeBranch(taxonNode, null, baseRank, includeUnpublished, propertyPaths);
     }
 
     /**
-     * @implements {@link IClassificationService#loadTreeBranch(TaxonNode, Rank, List)
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#loadTreeBranchTo(eu.etaxonomy.cdm.model.taxon.TaxonNode, eu.etaxonomy.cdm.model.name.Rank, java.util.List)
-     * FIXME Candidate for harmonization
-     * move to classification service
+     * {@inheritDoc}
      */
     @Override
-    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, Rank baseRank, List<String> propertyPaths){
+    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, TaxonNode subtree, Rank baseRank,
+            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
 
         TaxonNode thisNode = taxonNodeDao.load(taxonNode.getUuid(), propertyPaths);
-        List<TaxonNode> pathToRoot = new ArrayList<TaxonNode>();
+        if(baseRank != null){
+            baseRank = (Rank) termDao.load(baseRank.getUuid());
+        }
+        if (!includeUnpublished && thisNode.getTaxon() != null && !thisNode.getTaxon().isPublish()){
+            throw new UnpublishedException("Final taxon in tree branch is unpublished.");
+        }
+
+        List<TaxonNode> pathToRoot = new ArrayList<>();
         pathToRoot.add(thisNode);
 
         while(!thisNode.isTopmostNode()){
             //TODO why do we need to deproxy here?
             //     without this thisNode.getParent() will return NULL in
             //     some cases (environment dependend?) even if the parent exits
-            TaxonNode parentNode = CdmBase.deproxy(thisNode, TaxonNode.class).getParent();
+            TaxonNode parentNode = CdmBase.deproxy(thisNode).getParent();
 
             if(parentNode == null){
-                throw new NullPointerException("taxonNode " + thisNode + " must have a parent since it is not top most");
+                throw new NullPointerException("Taxon node " + thisNode + " must have a parent since it is not top most");
             }
             if(parentNode.getTaxon() == null){
-                throw new NullPointerException("The taxon associated with taxonNode " + parentNode + " is NULL");
+                throw new NullPointerException("The taxon associated with taxon node " + parentNode + " is NULL");
+            }
+            if(!includeUnpublished && !parentNode.getTaxon().isPublish()){
+                throw new UnpublishedException("Some taxon in tree branch is unpublished.");
             }
             if(parentNode.getTaxon().getName() == null){
                 throw new NullPointerException("The name of the taxon associated with taxonNode " + parentNode + " is NULL");
             }
 
-            Rank parentNodeRank = parentNode.getTaxon().getName() == null ? null : parentNode.getTaxon().getName().getRank();
+            Rank parentNodeRank = (parentNode.getTaxon().getName() == null) ? null : parentNode.getTaxon().getName().getRank();
             // stop if the next parent is higher than the baseRank
             if(baseRank != null && parentNodeRank != null && baseRank.isLower(parentNodeRank)){
                 break;
             }
+            if((subtree!= null && !subtree.isAncestor(parentNode) )){
+                break;
+            }
 
             pathToRoot.add(parentNode);
             thisNode = parentNode;
@@ -201,15 +310,28 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
     }
 
     @Override
-    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification, Rank baseRank, List<String> propertyPaths){
-        Classification tree = dao.load(classification.getUuid());
-        taxon = (Taxon) taxonDao.load(taxon.getUuid());
-        TaxonNode node = tree.getNode(taxon);
+    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification, Rank baseRank,
+            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
+        return loadTreeBranchToTaxon(taxon, classification, null, baseRank, includeUnpublished, propertyPaths);
+    }
+
+    @Override
+    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification,
+            TaxonNode subtree, Rank baseRank,
+            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
+
+        UUID nodeUuid = getTaxonNodeUuidByTaxonUuid(classification.getUuid(), taxon.getUuid());
+        TaxonNode node = taxonNodeService.find(nodeUuid);
         if(node == null){
             logger.warn("The specified taxon is not found in the given tree.");
             return null;
+        }else if (subtree != null && !node.isDescendant(subtree)){
+            //TODO handle as exception? E.g. FilterException, AccessDeniedException?
+            logger.warn("The specified taxon is not found for the given subtree.");
+            return null;
         }
-        return loadTreeBranch(node, baseRank, propertyPaths);
+
+        return loadTreeBranch(node, subtree, baseRank, includeUnpublished, propertyPaths);
     }
 
 
@@ -224,50 +346,60 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
     }
 
     @Override
-    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
-            Integer pageIndex, List<String> propertyPaths){
+    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid,
+            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths){
+        try {
+            return listChildNodesOfTaxon(taxonUuid, classificationUuid, null, includeUnpublished, pageSize, pageIndex, propertyPaths);
+        } catch (FilterException e) {
+            throw new RuntimeException(e);  //this should not happen as filter is null
+        }
+    }
+
+    @Override
+    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid, UUID subtreeUuid,
+            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) throws FilterException{
 
         Classification classification = dao.load(classificationUuid);
         Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
+        TaxonNode subtree = taxonNodeDao.load(subtreeUuid);
+        if (subtreeUuid != null && subtree == null){
+            throw new FilterException("Taxon node for subtree filter can not be found in database", true);
+        }
 
-        List<TaxonNode> results = dao.listChildrenOf(taxon, classification, pageSize, pageIndex, propertyPaths);
+        List<TaxonNode> results = dao.listChildrenOf(
+                taxon, classification, subtree, includeUnpublished, pageSize, pageIndex, propertyPaths);
         Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
         return results;
     }
 
     @Override
-    public Pager<TaxonNode> pageSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
-            Integer pageIndex, List<String> propertyPaths){
+    public Pager<TaxonNode> pageSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, boolean includeUnpublished,
+            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
 
         Classification classification = dao.load(classificationUuid);
         Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
 
-        long numberOfResults = dao.countSiblingsOf(taxon, classification);
+        long numberOfResults = dao.countSiblingsOf(taxon, classification, includeUnpublished);
 
         List<TaxonNode> results;
         if(PagerUtils.hasResultsInRange(numberOfResults, pageIndex, pageSize)) {
-            results = dao.listSiblingsOf(taxon, classification, pageSize, pageIndex, propertyPaths);
+            results = dao.listSiblingsOf(taxon, classification, includeUnpublished, pageSize, pageIndex, propertyPaths);
             Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
         } else {
             results = new ArrayList<>();
         }
 
-        return new DefaultPagerImpl<TaxonNode>(pageIndex, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageIndex, numberOfResults, pageSize, results);
     }
 
     @Override
-    public List<TaxonNode> listSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
-            Integer pageIndex, List<String> propertyPaths){
+    public List<TaxonNode> listSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, boolean includeUnpublished,
+            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
 
-        Pager<TaxonNode> pager = pageSiblingsOfTaxon(taxonUuid, classificationUuid, pageSize, pageIndex, propertyPaths);
+        Pager<TaxonNode> pager = pageSiblingsOfTaxon(taxonUuid, classificationUuid, includeUnpublished, pageSize, pageIndex, propertyPaths);
         return pager.getRecords();
     }
 
-    @Override
-    public TaxonNode getTaxonNodeByUuid(UUID uuid) {
-        return taxonNodeDao.findByUuid(uuid);
-    }
-
     @Override
     public ITaxonTreeNode getTreeNodeByUuid(UUID uuid){
         ITaxonTreeNode treeNode = taxonNodeDao.findByUuid(uuid);
@@ -278,6 +410,11 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         return treeNode;
     }
 
+    @Override
+    public TaxonNode getRootNode(UUID classificationUuid){
+        return dao.getRootNode(classificationUuid);
+    }
+
     @Override
     public List<Classification> listClassifications(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
         return dao.list(limit, start, orderHints, propertyPaths);
@@ -307,6 +444,14 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
         return taxonNodeDao.saveAll(taxonNodeCollection);
     }
 
+    @Override
+    public UUID saveClassification(Classification classification) {
+
+       taxonNodeDao.saveOrUpdateAll(classification.getAllNodes());
+       UUID result =dao.saveOrUpdate(classification);
+       return result;
+    }
+
     @Override
     public UUID saveTreeNode(ITaxonTreeNode treeNode) {
         if(treeNode instanceof Classification){
@@ -323,23 +468,23 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
     }
 
     @Override
-    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, List<UUID> excludeTaxa, Integer limit, String pattern) {
-        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid), excludeTaxa, limit, pattern);
+    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, Integer limit, String pattern, boolean searchForClassifications) {
+        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid),  limit, pattern, searchForClassifications);
     }
 
     @Override
-    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, List<UUID> excludeTaxa, Integer limit, String pattern) {
-        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, excludeTaxa, limit, pattern);
+    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification,  Integer limit, String pattern, boolean searchForClassifications) {
+        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification,  limit, pattern, searchForClassifications);
     }
 
     @Override
-    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, List<UUID> excludeTaxa) {
-        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid), excludeTaxa, null, null);
+    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, boolean searchForClassifications ) {
+        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid), null, null, searchForClassifications);
     }
 
     @Override
-    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, List<UUID> excludeTaxa) {
-        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, excludeTaxa, null, null);
+    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, boolean searchForClassifications ) {
+        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, null, null, searchForClassifications);
     }
 
     @Override
@@ -352,48 +497,32 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
             TaxonNode taxonNode, List<String> propertyPaths, int size,
             int height, int widthOrDuration, String[] mimeTypes) {
 
-        TreeMap<UUID, List<MediaRepresentation>> result = new TreeMap<UUID, List<MediaRepresentation>>();
-        List<Media> taxonMedia = new ArrayList<Media>();
-        List<MediaRepresentation> mediaRepresentations = new ArrayList<MediaRepresentation>();
+        TreeMap<UUID, List<MediaRepresentation>> result = new TreeMap<>();
+        List<MediaRepresentation> mediaRepresentations = new ArrayList<>();
 
         //add all media of the children to the result map
         if (taxonNode != null){
 
-            List<TaxonNode> nodes = new ArrayList<TaxonNode>();
+            List<TaxonNode> nodes = new ArrayList<>();
 
-            nodes.add(loadTaxonNode(taxonNode, propertyPaths));
+            nodes.add(loadTaxonNode(taxonNode.getUuid(), propertyPaths));
             nodes.addAll(loadChildNodesOfTaxonNode(taxonNode, propertyPaths));
 
-            if (nodes != null){
-                for(TaxonNode node : nodes){
-                    Taxon taxon = node.getTaxon();
-                    for (TaxonDescription taxonDescription: taxon.getDescriptions()){
-                        for (DescriptionElementBase descriptionElement: taxonDescription.getElements()){
-                            for(Media media : descriptionElement.getMedia()){
-                                taxonMedia.add(media);
-
-                                //find the best matching representation
-                                mediaRepresentations.add(MediaUtils.findBestMatchingRepresentation(media,null, size, height, widthOrDuration, mimeTypes));
-
-                            }
+            for(TaxonNode node : nodes){
+                Taxon taxon = node.getTaxon();
+                for (TaxonDescription taxonDescription: taxon.getDescriptions()){
+                    for (DescriptionElementBase descriptionElement: taxonDescription.getElements()){
+                        for(Media media : descriptionElement.getMedia()){
+                            //find the best matching representation
+                            mediaRepresentations.add(MediaUtils.findBestMatchingRepresentation(media,null, size, height, widthOrDuration, mimeTypes));
                         }
                     }
-                    result.put(taxon.getUuid(), mediaRepresentations);
-
                 }
+                result.put(taxon.getUuid(), mediaRepresentations);
             }
-
         }
 
         return result;
-
-    }
-
-    @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
@@ -416,11 +545,10 @@ 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){
@@ -440,7 +568,7 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
                        sortedGenusMap.put(genusOrUninomial, list);
                }else{
                        //create List for genus
-                       List<TaxonNode> list = new ArrayList<TaxonNode>();
+                       List<TaxonNode> list = new ArrayList<>();
                        list.add(node);
                        sortedGenusMap.put(genusOrUninomial, list);
                }
@@ -458,7 +586,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){
@@ -467,7 +595,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());
@@ -480,9 +608,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
@@ -511,10 +638,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);
                }
@@ -578,12 +704,362 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase<Classific
                return childNodes;
        }
 
-   /**
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ClassificationLookupDTO classificationLookup(Classification classification) {
+        return dao.classificationLookup(classification);
+    }
+
+
+    @Override
+    @Transactional
+    public DeleteResult delete(UUID classificationUuid, TaxonDeletionConfigurator config){
+        DeleteResult result = new DeleteResult();
+        Classification classification = dao.findByUuid(classificationUuid);
+        if (classification == null){
+            result.addException(new IllegalArgumentException("The classification does not exist in database."));
+            result.setAbort();
+            return result;
+        }
+        if (!classification.hasChildNodes()){
+            dao.delete(classification);
+            result.addDeletedObject(classification);
+            return result;
+        }
+        if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)){
+//            TaxonNode root = classification.getRootNode();
+//            result.includeResult(taxonNodeService.deleteTaxonNode(HibernateProxyHelper.deproxy(root), config));
+//            result.addDeletedObject(classification);
+            dao.delete(classification);
+            result.addDeletedObject(classification);
+            return result;
+        }
+
+
+        return result;
+    }
+
+    @Override
+    public List<GroupedTaxonDTO> groupTaxaByHigherTaxon(List<UUID> originalTaxonUuids, UUID classificationUuid, Rank minRank, Rank maxRank){
+        List<GroupedTaxonDTO> result = new ArrayList<>();
+
+        //get treeindex for each taxonUUID
+        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
+
+        //build treeindex list (or tree)
+        //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 (!treeIndexClosureStr.contains(currentIndex) && !split.startsWith(ITreeNode.treePrefix)){
+                    treeIndexClosureStr.add(currentIndex);
+                }
+            }
+        }
+
+        //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();
+        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<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));
+            lastTreeIndex = treeIndex;
+        }
+
+        //get taxonID for treeIndexes
+        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);
+            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{
+                    groupTreeIndex = groupTreeIndex.parent();
+//                    int index = groupIndex.substring(0, groupIndex.length()-1).lastIndexOf(ITreeNode.separator);
+//                    groupIndex = index < 0 ? null : groupIndex.substring(0, index+1);
+                }
+            }
+        }
+
+        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}
+     */
+    @Override
+    public UUID getTaxonNodeUuidByTaxonUuid(UUID classificationUuid, UUID taxonUuid) {
+        Map<UUID, UUID> map = dao.getTaxonNodeUuidByTaxonUuid(classificationUuid, Arrays.asList(taxonUuid));
+        UUID taxonNodeUuid = map.get(taxonUuid);
+        return taxonNodeUuid;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public TaxonInContextDTO getTaxonInContext(UUID classificationUuid, UUID taxonBaseUuid,
+            Boolean doChildren, Boolean doSynonyms, boolean includeUnpublished, List<UUID> ancestorMarkers,
+            NodeSortMode sortMode) {
+        TaxonInContextDTO result = new TaxonInContextDTO();
+
+        TaxonBase<?> taxonBase = taxonDao.load(taxonBaseUuid);
+        if (taxonBase == null){
+            throw new EntityNotFoundException("Taxon with uuid " + taxonBaseUuid + " not found in datasource");
+        }
+        boolean isSynonym = false;
+        Taxon acceptedTaxon;
+        if (taxonBase.isInstanceOf(Synonym.class)){
+            isSynonym = true;
+            Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
+            acceptedTaxon = synonym.getAcceptedTaxon();
+            if (acceptedTaxon == null) {
+                throw new EntityNotFoundException("Accepted taxon not found for synonym"  );
+            }
+            TaxonStatus taxonStatus = TaxonStatus.Synonym;
+            if (synonym.getName()!= null && acceptedTaxon.getName() != null
+                    && synonym.getName().getHomotypicalGroup().equals(acceptedTaxon.getName().getHomotypicalGroup())){
+                taxonStatus = TaxonStatus.SynonymObjective;
+            }
+            result.setTaxonStatus(taxonStatus);
+
+        }else{
+            acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
+            result.setTaxonStatus(TaxonStatus.Accepted);
+        }
+        UUID acceptedTaxonUuid = acceptedTaxon.getUuid();
+
+        UUID taxonNodeUuid = getTaxonNodeUuidByTaxonUuid(classificationUuid, acceptedTaxonUuid);
+        if (taxonNodeUuid == null) {
+            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){
+            result.setSecundumUuid(taxonBase.getSec().getUuid());
+            result.setSecundumLabel(taxonBase.getSec().getTitleCache());
+        }
+        result.setTaxonLabel(taxonBase.getTitleCache());
+
+        TaxonName name = taxonBase.getName();
+        result.setNameUuid(name.getUuid());
+        result.setNameLabel(name.getTitleCache());
+        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;
+        Integer pageSize = null;
+        Integer pageIndex = null;
+        Pager<TaxonNodeDto> children = taxonNodeService.pageChildNodesDTOs(taxonNodeUuid, recursive, includeUnpublished, doSynonyms,
+                sortMode, pageSize, pageIndex);
+
+        //children
+        if(! isSynonym) {
+            for (TaxonNodeDto childDto : children.getRecords()){
+                if (doChildren && childDto.getStatus().equals(TaxonStatus.Accepted)){
+                    EntityDTO<Taxon> child = new EntityDTO<Taxon>(childDto.getTaxonUuid(), childDto.getTitleCache());
+                    result.addChild(child);
+                }else if (doSynonyms && childDto.getStatus().isSynonym()){
+                    EntityDTO<Synonym> child = new EntityDTO<>(childDto.getTaxonUuid(), childDto.getTitleCache());
+                    result.addSynonym(child);
+                }
+            }
+        }else{
+            result.setAcceptedTaxonUuid(acceptedTaxonUuid);
+            String nameTitel = acceptedTaxon.getName() == null ? null : acceptedTaxon.getName().getTitleCache();
+            result.setAcceptedTaxonLabel(acceptedTaxon.getTitleCache());
+            result.setAcceptedNameLabel(nameTitel);
+        }
+
+        //marked ancestors
+        if (ancestorMarkers != null && !ancestorMarkers.isEmpty()){
+            @SuppressWarnings("rawtypes")
+            List<DefinedTermBase> markerTypesTerms = termDao.list(ancestorMarkers, pageSize, null, null, null);
+            List<MarkerType> markerTypes = new ArrayList<>();
+            for (DefinedTermBase<?> term : markerTypesTerms){
+                if (term.isInstanceOf(MarkerType.class)){
+                    markerTypes.add(CdmBase.deproxy(term, MarkerType.class));
+                }
+            }
+            if (! markerTypes.isEmpty()){
+                TaxonNode node = taxonNodeDao.findByUuid(taxonNodeUuid);
+                handleAncestorsForMarkersRecursive(result, markerTypes, node);
+            }
+        }
+
+        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
+     * @param node
+     */
+    private void handleAncestorsForMarkersRecursive(TaxonInContextDTO result, List<MarkerType> markerTypes, TaxonNode node) {
+       for (MarkerType type : markerTypes){
+            Taxon taxon = node.getTaxon();
+            if (taxon != null && taxon.hasMarker(type, true)){
+                String label =  taxon.getName() == null? taxon.getTitleCache() : taxon.getName().getTitleCache();
+                MarkedEntityDTO<Taxon> dto = new MarkedEntityDTO<>(type, true, taxon.getUuid(), label);
+                result.addMarkedAncestor(dto);
+            }
+        }
+        TaxonNode parentNode = node.getParent();
+        if (parentNode != null){
+            handleAncestorsForMarkersRecursive(result, markerTypes, parentNode);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
+            Classification classification) {
+        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, false);
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
-   public ClassificationLookupDTO classificationLookup(Classification classification) {
-       return dao.classificationLookup(classification);
-   }
+    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
+            UUID classificationUuid) {
+        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classificationUuid, false);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
+            UUID classificationUuid, Integer limit, String pattern) {
+        return  getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classificationUuid,  limit, pattern, false);
+    }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
+            Classification classification, Integer limit, String pattern) {
+        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, limit, pattern, false);
+    }
 }