cleanup
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonNodeServiceImpl.java
index 1d9c67efb0f6492ad8ecf2e4eed718ee45a71cec..68318b35349e5537c917e3474cb6887100e5b74a 100644 (file)
-// $Id$\r
-/**\r
-* Copyright (C) 2007 EDIT\r
-* European Distributed Institute of Taxonomy\r
-* http://www.e-taxonomy.eu\r
-*\r
-* The contents of this file are subject to the Mozilla Public License Version 1.1\r
-* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/\r
-\r
-package eu.etaxonomy.cdm.api.service;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.Comparator;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Set;\r
-import java.util.UUID;\r
-\r
-import org.apache.log4j.Logger;\r
-import org.springframework.beans.factory.annotation.Autowired;\r
-import org.springframework.stereotype.Service;\r
-import org.springframework.transaction.annotation.Transactional;\r
-\r
-import eu.etaxonomy.cdm.api.service.UpdateResult.Status;\r
-import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;\r
-import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;\r
-import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator;\r
-import eu.etaxonomy.cdm.api.service.dto.CdmEntityIdentifier;\r
-import eu.etaxonomy.cdm.api.service.pager.Pager;\r
-import eu.etaxonomy.cdm.api.service.pager.PagerUtils;\r
-import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
-import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
-import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
-import eu.etaxonomy.cdm.model.name.HomotypicalGroup;\r
-import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
-import eu.etaxonomy.cdm.model.reference.Reference;\r
-import eu.etaxonomy.cdm.model.taxon.Classification;\r
-import eu.etaxonomy.cdm.model.taxon.Synonym;\r
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;\r
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;\r
-import eu.etaxonomy.cdm.model.taxon.Taxon;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonNodeByNameComparator;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonNodeByRankAndNameComparator;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;\r
-import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;\r
-import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;\r
-import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;\r
-\r
-/**\r
- * @author n.hoffmann\r
- * @created Apr 9, 2010\r
- * @version 1.0\r
- */\r
-@Service\r
-@Transactional(readOnly = true)\r
-public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITaxonNodeDao> implements ITaxonNodeService{\r
-    private static final Logger logger = Logger.getLogger(TaxonNodeServiceImpl.class);\r
-\r
-    @Autowired\r
-    private IBeanInitializer defaultBeanInitializer;\r
-\r
-    private final Comparator<? super TaxonNode> taxonNodeComparator = new TaxonNodeByNameComparator();\r
-\r
-    @Autowired\r
-    private ITaxonService taxonService;\r
-\r
-    @Autowired\r
-    private IClassificationService classService;\r
-\r
-    @Autowired\r
-    private IDefinedTermDao termDao;\r
-\r
-    @Override\r
-    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,\r
-            List<String> propertyPaths, boolean recursive, NodeSortMode sortMode) {\r
-        taxonNode = dao.load(taxonNode.getUuid());\r
-        List<TaxonNode> childNodes;\r
-        if (recursive == true){\r
-               childNodes  = dao.listChildrenOf(taxonNode, null, null, null, recursive);\r
-        }else{\r
-               childNodes = new ArrayList<TaxonNode>(taxonNode.getChildNodes());\r
-        }\r
-        if (sortMode != null){\r
-            Comparator<TaxonNode> comparator = null;\r
-            if (sortMode.equals(NodeSortMode.NaturalOrder)){\r
-                comparator = new TaxonNaturalComparator();\r
-            } else if (sortMode.equals(NodeSortMode.AlphabeticalOrder)){\r
-               comparator = new TaxonNodeByNameComparator();\r
-            } else if (sortMode.equals(NodeSortMode.RankAndAlphabeticalOrder)){\r
-               comparator = new TaxonNodeByRankAndNameComparator();\r
-            }\r
-               Collections.sort(childNodes, comparator);\r
-        }\r
-        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);\r
-        return childNodes;\r
-    }\r
-\r
-    @Override\r
-    @Autowired\r
-    protected void setDao(ITaxonNodeDao dao) {\r
-        this.dao = dao;\r
-    }\r
-\r
-    @Override\r
-    @Transactional(readOnly = false)\r
-    public DeleteResult makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode, SynonymRelationshipType synonymRelationshipType, Reference citation, String citationMicroReference)  {\r
-\r
-\r
-        // TODO at the moment this method only moves synonym-, concept relations and descriptions to the new accepted taxon\r
-        // in a future version we also want to move cdm data like annotations, marker, so., but we will need a policy for that\r
-        if (oldTaxonNode == null || newAcceptedTaxonNode == null || oldTaxonNode.getTaxon().getName() == null){\r
-            throw new IllegalArgumentException("A mandatory parameter was null.");\r
-        }\r
-\r
-        if(oldTaxonNode.equals(newAcceptedTaxonNode)){\r
-            throw new IllegalArgumentException("Taxon can not be made synonym of its own.");\r
-        }\r
-\r
-\r
-        Classification classification = oldTaxonNode.getClassification();\r
-        Taxon oldTaxon = (Taxon) HibernateProxyHelper.deproxy(oldTaxonNode.getTaxon());\r
-        Taxon newAcceptedTaxon = (Taxon)this.taxonService.load(newAcceptedTaxonNode.getTaxon().getUuid());\r
-        // Move oldTaxon to newTaxon\r
-        //TaxonNameBase<?,?> synonymName = oldTaxon.getName();\r
-        TaxonNameBase<?,?> synonymName = (TaxonNameBase)HibernateProxyHelper.deproxy(oldTaxon.getName());\r
-        HomotypicalGroup group = synonymName.getHomotypicalGroup();\r
-        group = HibernateProxyHelper.deproxy(group, HomotypicalGroup.class);\r
-        if (synonymRelationshipType == null){\r
-            if (synonymName.isHomotypic(newAcceptedTaxon.getName())){\r
-                synonymRelationshipType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();\r
-            }else{\r
-                synonymRelationshipType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();\r
-            }\r
-        }\r
-\r
-        //set homotypic group\r
-        HomotypicalGroup newAcceptedTaxonHomotypicalgroup = newAcceptedTaxon.getHomotypicGroup();\r
-        newAcceptedTaxonHomotypicalgroup = HibernateProxyHelper.deproxy(newAcceptedTaxonHomotypicalgroup, HomotypicalGroup.class);\r
-        TaxonNameBase newAcceptedTaxonName = HibernateProxyHelper.deproxy(newAcceptedTaxon.getName(), TaxonNameBase.class);\r
-        // Move Synonym Relations to new Taxon\r
-        SynonymRelationship synonmyRelationship = newAcceptedTaxon.addSynonymName(synonymName,\r
-                synonymRelationshipType, citation, citationMicroReference);\r
-         HomotypicalGroup homotypicalGroupAcceptedTaxon = synonmyRelationship.getSynonym().getHomotypicGroup();\r
-        // Move Synonym Relations to new Taxon\r
-        // From ticket 3163 we can move taxon with accepted name having homotypic synonyms\r
-        List<Synonym> synonymsInHomotypicalGroup = null;\r
-\r
-        //the synonyms of the homotypical group of the old taxon\r
-        if (synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){\r
-               synonymsInHomotypicalGroup = oldTaxon.getSynonymsInGroup(group);\r
-        }\r
-\r
-        for(SynonymRelationship synRelation : oldTaxon.getSynonymRelations()){\r
-            SynonymRelationshipType srt;\r
-            if(synRelation.getSynonym().getName().getHomotypicalGroup()!= null\r
-                    && synRelation.getSynonym().getName().getHomotypicalGroup().equals(newAcceptedTaxonName.getHomotypicalGroup())) {\r
-                srt = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();\r
-            } else if(synRelation.getType() != null && synRelation.getType().equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())) {\r
-               if (synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){\r
-                       srt = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();\r
-               } else{\r
-                       srt = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();\r
-               }\r
-            } else {\r
-                srt = synRelation.getType();\r
-\r
-            }\r
-\r
-            newAcceptedTaxon.addSynonym(synRelation.getSynonym(),\r
-                    srt,\r
-                    synRelation.getCitation(),\r
-                    synRelation.getCitationMicroReference());\r
-\r
-            /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF())){\r
-               homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());\r
-            }*/\r
-\r
-        }\r
-\r
-\r
-\r
-\r
-\r
-        // CHILD NODES\r
-        if(oldTaxonNode.getChildNodes() != null && oldTaxonNode.getChildNodes().size() != 0){\r
-               List<TaxonNode> childNodes = new ArrayList<TaxonNode>();\r
-               for (TaxonNode childNode : oldTaxonNode.getChildNodes()){\r
-                       childNodes.add(childNode);\r
-               }\r
-            for(TaxonNode childNode :childNodes){\r
-                newAcceptedTaxonNode.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference()); // childNode.getSynonymToBeUsed()\r
-            }\r
-        }\r
-\r
-        //Move Taxon RelationShips to new Taxon\r
-        Set<TaxonRelationship> obsoleteTaxonRelationships = new HashSet<TaxonRelationship>();\r
-        for(TaxonRelationship taxonRelationship : oldTaxon.getTaxonRelations()){\r
-            Taxon fromTaxon = (Taxon) HibernateProxyHelper.deproxy(taxonRelationship.getFromTaxon());\r
-            Taxon toTaxon = (Taxon) HibernateProxyHelper.deproxy(taxonRelationship.getToTaxon());\r
-            if (fromTaxon == oldTaxon){\r
-                newAcceptedTaxon.addTaxonRelation(taxonRelationship.getToTaxon(), taxonRelationship.getType(),\r
-                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());\r
-\r
-            }else if(toTaxon == oldTaxon){\r
-               fromTaxon.addTaxonRelation(newAcceptedTaxon, taxonRelationship.getType(),\r
-                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());\r
-               taxonService.saveOrUpdate(fromTaxon);\r
-\r
-            }else{\r
-                logger.warn("Taxon is not part of its own Taxonrelationship");\r
-            }\r
-            // Remove old relationships\r
-\r
-            fromTaxon.removeTaxonRelation(taxonRelationship);\r
-            toTaxon.removeTaxonRelation(taxonRelationship);\r
-            taxonRelationship.setToTaxon(null);\r
-            taxonRelationship.setFromTaxon(null);\r
-        }\r
-\r
-\r
-        //Move descriptions to new taxon\r
-        List<TaxonDescription> descriptions = new ArrayList<TaxonDescription>( oldTaxon.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())\r
-        for(TaxonDescription description : descriptions){\r
-            String message = "Description copied from former accepted taxon: %s (Old title: %s)";\r
-            message = String.format(message, oldTaxon.getTitleCache(), description.getTitleCache());\r
-            description.setTitleCache(message, true);\r
-            //oldTaxon.removeDescription(description, false);\r
-            newAcceptedTaxon.addDescription(description);\r
-        }\r
-        oldTaxon.clearDescriptions();\r
-\r
-        taxonService.update(newAcceptedTaxon);\r
-\r
-        taxonService.update(oldTaxon);\r
-\r
-        TaxonDeletionConfigurator conf = new TaxonDeletionConfigurator();\r
-        conf.setDeleteSynonymsIfPossible(false);\r
-        DeleteResult result = taxonService.isDeletable(oldTaxon, conf);\r
-        conf.setDeleteNameIfPossible(false);\r
-\r
-        if (result.isOk()){\r
-                result = taxonService.deleteTaxon(oldTaxon.getUuid(), conf, classification.getUuid());\r
-        }else{\r
-               result.setStatus(Status.OK);\r
-               TaxonNodeDeletionConfigurator config = new TaxonNodeDeletionConfigurator();\r
-               config.setDeleteElement(false);\r
-               conf.setTaxonNodeConfig(config);\r
-               result.includeResult(deleteTaxonNode(oldTaxonNode, conf));\r
-        }\r
-        result.addUpdatedObject(newAcceptedTaxon);\r
-        result.addUpdatedObject(oldTaxon);\r
-\r
-        //oldTaxonNode.delete();\r
-        return result;\r
-    }\r
-\r
-\r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#makeTaxonNodeASynonymOfAnotherTaxonNode(java.util.UUID, java.util.UUID, java.util.UUID, java.util.UUID, java.lang.String)\r
-     */\r
-    @Override\r
-    @Transactional(readOnly = false)\r
-    public UpdateResult makeTaxonNodeASynonymOfAnotherTaxonNode(UUID oldTaxonNodeUuid,\r
-            UUID newAcceptedTaxonNodeUUID,\r
-            SynonymRelationshipType synonymRelationshipType,\r
-            Reference citation,\r
-            String citationMicroReference) {\r
-\r
-        TaxonNode oldTaxonNode = dao.load(oldTaxonNodeUuid);\r
-        TaxonNode oldTaxonParentNode = oldTaxonNode.getParent();\r
-        TaxonNode newTaxonNode = dao.load(newAcceptedTaxonNodeUUID);\r
-\r
-        UpdateResult result = makeTaxonNodeASynonymOfAnotherTaxonNode(oldTaxonNode,\r
-                newTaxonNode,\r
-                synonymRelationshipType,\r
-                citation,\r
-                citationMicroReference);\r
-        result.addUpdatedCdmId(new CdmEntityIdentifier(oldTaxonParentNode.getId(), TaxonNode.class));\r
-        result.addUpdatedCdmId(new CdmEntityIdentifier(newTaxonNode.getId(), TaxonNode.class));\r
-        result.setCdmEntity(oldTaxonParentNode);\r
-        return result;\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNodes(java.util.List)\r
-     */\r
-    @Override\r
-    @Transactional(readOnly = false)\r
-    public DeleteResult deleteTaxonNodes(List<TaxonNode> list, TaxonDeletionConfigurator config) {\r
-\r
-        if (config == null){\r
-               config = new TaxonDeletionConfigurator();\r
-        }\r
-        DeleteResult result = new DeleteResult();\r
-        List<UUID> deletedUUIDs = new ArrayList<UUID>();\r
-        Classification classification = null;\r
-        List<TaxonNode> taxonNodes = new ArrayList<TaxonNode>(list);\r
-        for (TaxonNode treeNode:taxonNodes){\r
-               if (treeNode != null){\r
-\r
-                       TaxonNode taxonNode;\r
-                   taxonNode = HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);\r
-                   TaxonNode parent = taxonNode.getParent();\r
-                       //check whether the node has children or the children are already deleted\r
-                   if(taxonNode.hasChildNodes()) {\r
-                       List<TaxonNode> children = new ArrayList<TaxonNode> ();\r
-                       List<TaxonNode> childNodesList = taxonNode.getChildNodes();\r
-                               children.addAll(childNodesList);\r
-                               int compare = config.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling.DELETE);\r
-                               boolean childHandling = (compare == 0)? true: false;\r
-                       if (childHandling){\r
-                               boolean changeDeleteTaxon = false;\r
-                               if (!config.getTaxonNodeConfig().isDeleteTaxon()){\r
-                                       config.getTaxonNodeConfig().setDeleteTaxon(true);\r
-                                       changeDeleteTaxon = true;\r
-                               }\r
-                               DeleteResult resultNodes = deleteTaxonNodes(children, config);\r
-                               if (!resultNodes.isOk()){\r
-                            result.addExceptions(resultNodes.getExceptions());\r
-                            result.setStatus(resultNodes.getStatus());\r
-                        }\r
-                               if (changeDeleteTaxon){\r
-                                       config.getTaxonNodeConfig().setDeleteTaxon(false);\r
-                               }\r
-\r
-                       } else {\r
-                               //move the children to the parent\r
-\r
-                               for (TaxonNode child: childNodesList){\r
-                                       parent.addChildNode(child, child.getReference(), child.getMicroReference());\r
-                               }\r
-\r
-                       }\r
-               }\r
-\r
-                   classification = taxonNode.getClassification();\r
-\r
-                   if (classification.getRootNode().equals(taxonNode)){\r
-                       classification.removeRootNode();\r
-                       classification = null;\r
-                   }else if (classification.getChildNodes().contains(taxonNode)){\r
-                       Taxon taxon = taxonNode.getTaxon();\r
-                       classification.deleteChildNode(taxonNode);\r
-\r
-                       //node is rootNode\r
-                       if (taxon != null){\r
-\r
-                               if (config.getTaxonNodeConfig().isDeleteTaxon()){\r
-                                   taxonService.saveOrUpdate(taxon);\r
-                                   saveOrUpdate(taxonNode);\r
-\r
-                                       TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();\r
-                                       DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, classification.getUuid());\r
-                                       if (!resultTaxon.isOk()){\r
-                                result.addExceptions(resultTaxon.getExceptions());\r
-                                result.setStatus(resultTaxon.getStatus());\r
-                            }\r
-\r
-                               }\r
-                       }\r
-                       classification = null;\r
-\r
-                   } else {\r
-                       classification = null;\r
-                       Taxon taxon = taxonNode.getTaxon();\r
-                       taxon = HibernateProxyHelper.deproxy(taxon, Taxon.class);\r
-                       if (taxon != null){\r
-                               taxon.removeTaxonNode(taxonNode);\r
-                               if (config.getTaxonNodeConfig().isDeleteTaxon()){\r
-                                       TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();\r
-                                       saveOrUpdate(taxonNode);\r
-                                       taxonService.saveOrUpdate(taxon);\r
-                                       DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, null);\r
-\r
-                            if (!resultTaxon.isOk()){\r
-                                result.addExceptions(resultTaxon.getExceptions());\r
-                                result.setStatus(resultTaxon.getStatus());\r
-                            }\r
-                               }\r
-                       }\r
-\r
-                   }\r
-\r
-                   result.addUpdatedObject(parent);\r
-                   if(result.getCdmEntity() == null){\r
-                       result.setCdmEntity(taxonNode);\r
-                }\r
-                   UUID uuid = dao.delete(taxonNode);\r
-                   logger.debug("Deleted node " +uuid.toString());\r
-\r
-               }\r
-        }\r
-        /*if (classification != null){\r
-            result.addUpdatedObject(classification);\r
-               DeleteResult resultClassification = classService.delete(classification);\r
-                if (!resultClassification.isOk()){\r
-                 result.addExceptions(resultClassification.getExceptions());\r
-                 result.setStatus(resultClassification.getStatus());\r
-             }\r
-        }*/\r
-        return result;\r
-\r
-    }\r
-\r
-\r
-    @Override\r
-    @Transactional(readOnly = false)\r
-    public DeleteResult deleteTaxonNodes(Collection<UUID> nodeUuids, TaxonDeletionConfigurator config) {\r
-        List<TaxonNode> nodes = new ArrayList<TaxonNode>();\r
-        for(UUID nodeUuid : nodeUuids) {\r
-            nodes.add(dao.load(nodeUuid));\r
-        }\r
-        return deleteTaxonNodes(nodes, config);\r
-    }\r
-\r
-\r
-\r
-    @Override\r
-    @Transactional(readOnly = false)\r
-    public DeleteResult deleteTaxonNode(UUID nodeUUID, TaxonDeletionConfigurator config) {\r
-\r
-       TaxonNode node = HibernateProxyHelper.deproxy(dao.load(nodeUUID), TaxonNode.class);\r
-       return deleteTaxonNode(node, config);\r
-    }\r
-\r
-    @Override\r
-    @Transactional(readOnly = false)\r
-    public DeleteResult deleteTaxonNode(TaxonNode node, TaxonDeletionConfigurator config) {\r
-        DeleteResult result = new DeleteResult();\r
-        if (node == null){\r
-            result.setAbort();\r
-            result.addException(new Exception("The TaxonNode was already deleted."));\r
-            return result;\r
-        }\r
-        Taxon taxon = null;\r
-        try{\r
-            taxon = (Taxon)HibernateProxyHelper.deproxy(node.getTaxon());\r
-        }catch(NullPointerException e){\r
-            result.setAbort();\r
-            result.addException(new Exception("The Taxon was already deleted."));\r
-\r
-        }\r
-       TaxonNode parent = HibernateProxyHelper.deproxy(node.getParent(), TaxonNode.class);\r
-       if (config == null){\r
-               config = new TaxonDeletionConfigurator();\r
-       }\r
-\r
-\r
-\r
-       if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.MOVE_TO_PARENT)){\r
-          Object[] children = node.getChildNodes().toArray();\r
-          TaxonNode childNode;\r
-          for (Object child: children){\r
-              childNode = (TaxonNode) child;\r
-              parent.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference());\r
-          }\r
-       }else{\r
-           deleteTaxonNodes(node.getChildNodes(), config);\r
-       }\r
-\r
-       if (taxon != null){\r
-               if (config.getTaxonNodeConfig().isDeleteTaxon() && (config.isDeleteInAllClassifications() || taxon.getTaxonNodes().size() == 1)){\r
-                       result = taxonService.deleteTaxon(taxon.getUuid(), config, node.getClassification().getUuid());\r
-                       result.addUpdatedObject(parent);\r
-                       if (result.isOk()){\r
-                               return result;\r
-                       }\r
-               } else {\r
-                   result.addUpdatedObject(taxon);\r
-               }\r
-       }\r
-       result.setCdmEntity(node);\r
-       boolean success = taxon.removeTaxonNode(node);\r
-       dao.save(parent);\r
-       taxonService.saveOrUpdate(taxon);\r
-       result.addUpdatedObject(parent);\r
-\r
-       if (success){\r
-                       result.setStatus(Status.OK);\r
-                       parent = HibernateProxyHelper.deproxy(parent, TaxonNode.class);\r
-                       int index = parent.getChildNodes().indexOf(node);\r
-                       if (index > -1){\r
-                           parent.removeChild(index);\r
-                       }\r
-               if (!dao.delete(node, config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)).equals(null)){\r
-                       return result;\r
-               } else {\r
-                       result.setError();\r
-                       return result;\r
-               }\r
-       }else{\r
-           if (dao.findByUuid(node.getUuid()) != null){\r
-                       result.setError();\r
-                       result.addException(new Exception("The node can not be removed from the taxon."));\r
-               }\r
-               return result;\r
-       }\r
-\r
-\r
-\r
-    }\r
-\r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#listAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification, int, int)\r
-     */\r
-    @Override\r
-    public List<TaxonNode> listAllNodesForClassification(Classification classification, Integer start, Integer end) {\r
-        return dao.getTaxonOfAcceptedTaxaByClassification(classification, start, end);\r
-    }\r
-\r
-    @Override\r
-    public int countAllNodesForClassification(Classification classification) {\r
-        return dao.countTaxonOfAcceptedTaxaByClassification(classification);\r
-    }\r
-\r
-    @Override\r
-    @Transactional\r
-    public UpdateResult moveTaxonNode(UUID taxonNodeUuid, UUID targetNodeUuid, boolean isParent){\r
-        TaxonNode taxonNode = dao.load(taxonNodeUuid);\r
-       TaxonNode targetNode = dao.load(targetNodeUuid);\r
-       return moveTaxonNode(taxonNode, targetNode, isParent);\r
-    }\r
-\r
-    @Override\r
-    @Transactional\r
-    public UpdateResult moveTaxonNode(TaxonNode taxonNode, TaxonNode newParent, boolean isParent){\r
-        UpdateResult result = new UpdateResult();\r
-\r
-        Integer sortIndex;\r
-        if (isParent){\r
-\r
-            sortIndex = newParent.getChildNodes().size();\r
-        }else{\r
-            sortIndex = newParent.getSortIndex() +1;\r
-            newParent = newParent.getParent();\r
-        }\r
-        result.addUpdatedObject(newParent);\r
-        result.addUpdatedObject(taxonNode.getParent());\r
-        result.setCdmEntity(taxonNode);\r
-        newParent.addChildNode(taxonNode, sortIndex, taxonNode.getReference(),  taxonNode.getMicroReference());\r
-        dao.saveOrUpdate(newParent);\r
-\r
-        return result;\r
-    }\r
-\r
-\r
-\r
-    @Override\r
-    @Transactional\r
-    public UpdateResult moveTaxonNodes(Set<UUID> taxonNodeUuids, UUID newParentNodeUuid, boolean isParent){\r
-        UpdateResult result = new UpdateResult();\r
-        TaxonNode targetNode = dao.load(newParentNodeUuid);\r
-        for (UUID taxonNodeUuid: taxonNodeUuids){\r
-            TaxonNode taxonNode = dao.load(taxonNodeUuid);\r
-            result.includeResult(moveTaxonNode(taxonNode,targetNode, isParent));\r
-        }\r
-        return result;\r
-    }\r
-\r
-    @Override\r
-    public Pager<TaxonNodeAgentRelation> pageTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,\r
-            UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {\r
-\r
-\r
-        List<TaxonNodeAgentRelation> records = null;\r
-\r
-        long count = dao.countTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid);\r
-        if(PagerUtils.hasResultsInRange(count, pageIndex, pageSize)) {\r
-            records = dao.listTaxonNodeAgentRelations(taxonUuid, classificationUuid,\r
-                    agentUuid, rankUuid, relTypeUuid, PagerUtils.startFor(pageSize, pageIndex), PagerUtils.limitFor(pageSize), propertyPaths);\r
-        }\r
-\r
-        Pager<TaxonNodeAgentRelation> pager = new DefaultPagerImpl<TaxonNodeAgentRelation>(pageIndex, count, pageSize, records);\r
-        return pager;\r
-    }\r
-\r
-    @Override\r
-    @Transactional\r
-    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, Taxon newTaxon, Reference ref, String microref){\r
-        UpdateResult result = new UpdateResult();\r
-        TaxonNode parent = dao.load(parentNodeUuid);\r
-        TaxonNode child = null;\r
-        try{\r
-            child = parent.addChildTaxon(newTaxon, parent.getReference(), parent.getMicroReference());\r
-        }catch(Exception e){\r
-            logger.error("TaxonNode could not be created.");\r
-        }\r
-//        child = dao.save(child);\r
-\r
-        dao.saveOrUpdate(parent);\r
-        result.addUpdatedObject(parent);\r
-        result.setCdmEntity(child);\r
-        return result;\r
-\r
-    }\r
-\r
-}\r
+// $Id$
+/**
+* Copyright (C) 2007 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+
+package eu.etaxonomy.cdm.api.service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+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.UpdateResult.Status;
+import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;
+import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
+import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator;
+import eu.etaxonomy.cdm.api.service.dto.CdmEntityIdentifier;
+import eu.etaxonomy.cdm.api.service.pager.Pager;
+import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
+import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
+import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
+import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
+import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.common.DefinedTerm;
+import eu.etaxonomy.cdm.model.description.TaxonDescription;
+import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
+import eu.etaxonomy.cdm.model.name.TaxonNameBase;
+import eu.etaxonomy.cdm.model.reference.Reference;
+import eu.etaxonomy.cdm.model.taxon.Classification;
+import eu.etaxonomy.cdm.model.taxon.HomotypicGroupTaxonComparator;
+import eu.etaxonomy.cdm.model.taxon.Synonym;
+import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
+import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
+import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;
+import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
+import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
+import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
+import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
+import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
+
+/**
+ * @author n.hoffmann
+ * @created Apr 9, 2010
+ * @version 1.0
+ */
+@Service
+@Transactional(readOnly = true)
+public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITaxonNodeDao> implements ITaxonNodeService{
+    private static final Logger logger = Logger.getLogger(TaxonNodeServiceImpl.class);
+
+    @Autowired
+    private IBeanInitializer defaultBeanInitializer;
+
+    @Autowired
+    private ITaxonService taxonService;
+
+    @Autowired
+    private IAgentService agentService;
+
+    @Override
+    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
+            List<String> propertyPaths, boolean recursive, NodeSortMode sortMode) {
+
+        getSession().refresh(taxonNode);
+        List<TaxonNode> childNodes;
+        if (recursive == true){
+               childNodes  = dao.listChildrenOf(taxonNode, null, null, null, recursive);
+        }else{
+               childNodes = new ArrayList<TaxonNode>(taxonNode.getChildNodes());
+        }
+
+        HHH_9751_Util.removeAllNull(childNodes);
+
+        if (sortMode != null){
+            Comparator<TaxonNode> comparator = sortMode.newComparator();
+               Collections.sort(childNodes, comparator);
+        }
+        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
+        return childNodes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Pager<TaxonNodeDto> pageChildNodesDTOs(UUID taxonNodeUuid, boolean recursive,
+            boolean doSynonyms, NodeSortMode sortMode,
+            Integer pageSize, Integer pageIndex) {
+
+        TaxonNode parentNode = dao.load(taxonNodeUuid);
+
+        List<CdmBase> allRecords = new ArrayList<>();
+
+        //acceptedTaxa
+        List<TaxonNode> childNodes = loadChildNodesOfTaxonNode(parentNode, null, recursive, sortMode);
+        allRecords.addAll(childNodes);
+
+        //add synonyms if pager is not yet full synonyms
+        List<Synonym> synList = new ArrayList<>(parentNode.getTaxon().getSynonyms());
+        Collections.sort(synList, new HomotypicGroupTaxonComparator(null));
+        //TODO: test sorting
+
+        allRecords.addAll(synList);
+
+
+        List<TaxonNodeDto> dtos = new ArrayList<>(pageSize);
+        int start = PagerUtils.startFor(pageSize, pageIndex);
+        int limit = PagerUtils.limitFor(pageSize);
+        Long totalCount = Long.valueOf(allRecords.size());
+
+        if(PagerUtils.hasResultsInRange(totalCount, pageIndex, pageSize)) {
+            TaxonNameBase<?,?> parentName = null;
+
+            for(int i = start; i < Math.min(totalCount, start + limit); i++) {
+                CdmBase record = allRecords.get(i);
+
+                if (record.isInstanceOf(TaxonNode.class)){
+                    dtos.add(new TaxonNodeDto(CdmBase.deproxy(record, TaxonNode.class)));
+                }else if (record.isInstanceOf(Synonym.class)){
+                    Synonym synonym = CdmBase.deproxy(record, Synonym.class);
+                    parentName = parentName == null? parentNode.getTaxon().getName(): parentName;
+                    boolean isHomotypic = synonym.getName().isHomotypic(parentName);
+                    dtos.add(new TaxonNodeDto(synonym, isHomotypic));
+                }
+            }
+        }
+
+        return new DefaultPagerImpl<TaxonNodeDto>(pageIndex, totalCount, pageSize , dtos);
+    }
+
+    @Override
+    public TaxonNodeDto parentDto(UUID taxonNodeUuid) {
+        TaxonNode taxonNode = dao.load(taxonNodeUuid);
+        if(taxonNode.getParent() != null) {
+            return new TaxonNodeDto(taxonNode.getParent());
+        }
+        return null;
+    }
+
+    @Override
+    @Autowired
+    protected void setDao(ITaxonNodeDao dao) {
+        this.dao = dao;
+    }
+
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode, SynonymRelationshipType synonymRelationshipType, Reference citation, String citationMicroReference)  {
+
+
+        // TODO at the moment this method only moves synonym-, concept relations and descriptions to the new accepted taxon
+        // in a future version we also want to move cdm data like annotations, marker, so., but we will need a policy for that
+        if (oldTaxonNode == null || newAcceptedTaxonNode == null || oldTaxonNode.getTaxon().getName() == null){
+            throw new IllegalArgumentException("A mandatory parameter was null.");
+        }
+
+        if(oldTaxonNode.equals(newAcceptedTaxonNode)){
+            throw new IllegalArgumentException("Taxon can not be made synonym of its own.");
+        }
+
+
+        Classification classification = oldTaxonNode.getClassification();
+        Taxon oldTaxon = HibernateProxyHelper.deproxy(oldTaxonNode.getTaxon());
+        Taxon newAcceptedTaxon = (Taxon)this.taxonService.load(newAcceptedTaxonNode.getTaxon().getUuid());
+        // Move oldTaxon to newTaxon
+        //TaxonNameBase<?,?> synonymName = oldTaxon.getName();
+        TaxonNameBase<?,?> synonymName = HibernateProxyHelper.deproxy(oldTaxon.getName());
+        HomotypicalGroup group = synonymName.getHomotypicalGroup();
+        group = HibernateProxyHelper.deproxy(group, HomotypicalGroup.class);
+        if (synonymRelationshipType == null){
+            if (synonymName.isHomotypic(newAcceptedTaxon.getName())){
+                synonymRelationshipType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
+            }else{
+                synonymRelationshipType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
+            }
+        }
+
+        //set homotypic group
+        HomotypicalGroup newAcceptedTaxonHomotypicalgroup = newAcceptedTaxon.getHomotypicGroup();
+        newAcceptedTaxonHomotypicalgroup = HibernateProxyHelper.deproxy(newAcceptedTaxonHomotypicalgroup, HomotypicalGroup.class);
+        TaxonNameBase newAcceptedTaxonName = HibernateProxyHelper.deproxy(newAcceptedTaxon.getName(), TaxonNameBase.class);
+        // Move Synonym Relations to new Taxon
+        SynonymRelationship synonmyRelationship = newAcceptedTaxon.addSynonymName(synonymName,
+                synonymRelationshipType, citation, citationMicroReference);
+         HomotypicalGroup homotypicalGroupAcceptedTaxon = synonmyRelationship.getSynonym().getHomotypicGroup();
+        // Move Synonym Relations to new Taxon
+        // From ticket 3163 we can move taxon with accepted name having homotypic synonyms
+        List<Synonym> synonymsInHomotypicalGroup = null;
+
+        //the synonyms of the homotypical group of the old taxon
+        if (synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
+               synonymsInHomotypicalGroup = oldTaxon.getSynonymsInGroup(group);
+        }
+
+        for(SynonymRelationship synRelation : oldTaxon.getSynonymRelations()){
+            SynonymRelationshipType srt;
+            if(synRelation.getSynonym().getName().getHomotypicalGroup()!= null
+                    && synRelation.getSynonym().getName().getHomotypicalGroup().equals(newAcceptedTaxonName.getHomotypicalGroup())) {
+                srt = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
+            } else if(synRelation.getType() != null && synRelation.getType().equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())) {
+               if (synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
+                       srt = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
+               } else{
+                       srt = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
+               }
+            } else {
+                srt = synRelation.getType();
+
+            }
+
+            newAcceptedTaxon.addSynonym(synRelation.getSynonym(),
+                    srt,
+                    synRelation.getCitation(),
+                    synRelation.getCitationMicroReference());
+
+            /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF())){
+               homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
+            }*/
+
+        }
+
+
+
+
+
+        // CHILD NODES
+        if(oldTaxonNode.getChildNodes() != null && oldTaxonNode.getChildNodes().size() != 0){
+               List<TaxonNode> childNodes = new ArrayList<TaxonNode>();
+               for (TaxonNode childNode : oldTaxonNode.getChildNodes()){
+                       childNodes.add(childNode);
+               }
+            for(TaxonNode childNode :childNodes){
+                newAcceptedTaxonNode.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference()); // childNode.getSynonymToBeUsed()
+            }
+        }
+
+        //Move Taxon RelationShips to new Taxon
+        Set<TaxonRelationship> obsoleteTaxonRelationships = new HashSet<TaxonRelationship>();
+        for(TaxonRelationship taxonRelationship : oldTaxon.getTaxonRelations()){
+            Taxon fromTaxon = HibernateProxyHelper.deproxy(taxonRelationship.getFromTaxon());
+            Taxon toTaxon = HibernateProxyHelper.deproxy(taxonRelationship.getToTaxon());
+            if (fromTaxon == oldTaxon){
+                newAcceptedTaxon.addTaxonRelation(taxonRelationship.getToTaxon(), taxonRelationship.getType(),
+                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
+
+            }else if(toTaxon == oldTaxon){
+               fromTaxon.addTaxonRelation(newAcceptedTaxon, taxonRelationship.getType(),
+                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
+               taxonService.saveOrUpdate(fromTaxon);
+
+            }else{
+                logger.warn("Taxon is not part of its own Taxonrelationship");
+            }
+            // Remove old relationships
+
+            fromTaxon.removeTaxonRelation(taxonRelationship);
+            toTaxon.removeTaxonRelation(taxonRelationship);
+            taxonRelationship.setToTaxon(null);
+            taxonRelationship.setFromTaxon(null);
+        }
+
+
+        //Move descriptions to new taxon
+        List<TaxonDescription> descriptions = new ArrayList<TaxonDescription>( oldTaxon.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())
+        for(TaxonDescription description : descriptions){
+            String message = "Description copied from former accepted taxon: %s (Old title: %s)";
+            message = String.format(message, oldTaxon.getTitleCache(), description.getTitleCache());
+            description.setTitleCache(message, true);
+            //oldTaxon.removeDescription(description, false);
+            newAcceptedTaxon.addDescription(description);
+        }
+        oldTaxon.clearDescriptions();
+
+        taxonService.update(newAcceptedTaxon);
+
+        taxonService.update(oldTaxon);
+
+        TaxonDeletionConfigurator conf = new TaxonDeletionConfigurator();
+        conf.setDeleteSynonymsIfPossible(false);
+        DeleteResult result = taxonService.isDeletable(oldTaxon, conf);
+        conf.setDeleteNameIfPossible(false);
+
+        if (result.isOk()){
+                result = taxonService.deleteTaxon(oldTaxon.getUuid(), conf, classification.getUuid());
+        }else{
+               result.setStatus(Status.OK);
+               TaxonNodeDeletionConfigurator config = new TaxonNodeDeletionConfigurator();
+               config.setDeleteElement(false);
+               conf.setTaxonNodeConfig(config);
+               result.includeResult(deleteTaxonNode(oldTaxonNode, conf));
+        }
+        result.addUpdatedObject(newAcceptedTaxon);
+        result.addUpdatedObject(oldTaxon);
+
+        //oldTaxonNode.delete();
+        return result;
+    }
+
+
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#makeTaxonNodeASynonymOfAnotherTaxonNode(java.util.UUID, java.util.UUID, java.util.UUID, java.util.UUID, java.lang.String)
+     */
+    @Override
+    @Transactional(readOnly = false)
+    public UpdateResult makeTaxonNodeASynonymOfAnotherTaxonNode(UUID oldTaxonNodeUuid,
+            UUID newAcceptedTaxonNodeUUID,
+            SynonymRelationshipType synonymRelationshipType,
+            Reference citation,
+            String citationMicroReference) {
+
+        TaxonNode oldTaxonNode = dao.load(oldTaxonNodeUuid);
+        TaxonNode oldTaxonParentNode = oldTaxonNode.getParent();
+        TaxonNode newTaxonNode = dao.load(newAcceptedTaxonNodeUUID);
+
+        UpdateResult result = makeTaxonNodeASynonymOfAnotherTaxonNode(oldTaxonNode,
+                newTaxonNode,
+                synonymRelationshipType,
+                citation,
+                citationMicroReference);
+        result.addUpdatedCdmId(new CdmEntityIdentifier(oldTaxonParentNode.getId(), TaxonNode.class));
+        result.addUpdatedCdmId(new CdmEntityIdentifier(newTaxonNode.getId(), TaxonNode.class));
+        result.setCdmEntity(oldTaxonParentNode);
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNodes(java.util.List)
+     */
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult deleteTaxonNodes(List<TaxonNode> list, TaxonDeletionConfigurator config) {
+
+        if (config == null){
+               config = new TaxonDeletionConfigurator();
+        }
+        DeleteResult result = new DeleteResult();
+        List<UUID> deletedUUIDs = new ArrayList<UUID>();
+        Classification classification = null;
+        List<TaxonNode> taxonNodes = new ArrayList<TaxonNode>(list);
+        for (TaxonNode treeNode:taxonNodes){
+               if (treeNode != null){
+
+                       TaxonNode taxonNode;
+                   taxonNode = HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);
+                   TaxonNode parent = taxonNode.getParent();
+                       //check whether the node has children or the children are already deleted
+                   if(taxonNode.hasChildNodes()) {
+                       List<TaxonNode> children = new ArrayList<TaxonNode> ();
+                       List<TaxonNode> childNodesList = taxonNode.getChildNodes();
+                               children.addAll(childNodesList);
+                               int compare = config.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling.DELETE);
+                               boolean childHandling = (compare == 0)? true: false;
+                       if (childHandling){
+                               boolean changeDeleteTaxon = false;
+                               if (!config.getTaxonNodeConfig().isDeleteTaxon()){
+                                       config.getTaxonNodeConfig().setDeleteTaxon(true);
+                                       changeDeleteTaxon = true;
+                               }
+                               DeleteResult resultNodes = deleteTaxonNodes(children, config);
+                               if (!resultNodes.isOk()){
+                            result.addExceptions(resultNodes.getExceptions());
+                            result.setStatus(resultNodes.getStatus());
+                        }
+                               if (changeDeleteTaxon){
+                                       config.getTaxonNodeConfig().setDeleteTaxon(false);
+                               }
+
+                       } else {
+                               //move the children to the parent
+
+                               for (TaxonNode child: childNodesList){
+                                       parent.addChildNode(child, child.getReference(), child.getMicroReference());
+                               }
+
+                       }
+               }
+
+                   classification = taxonNode.getClassification();
+
+                   if (classification.getRootNode().equals(taxonNode)){
+                       classification.removeRootNode();
+                       classification = null;
+                   }else if (classification.getChildNodes().contains(taxonNode)){
+                       Taxon taxon = taxonNode.getTaxon();
+                       classification.deleteChildNode(taxonNode);
+
+                       //node is rootNode
+                       if (taxon != null){
+
+                               if (config.getTaxonNodeConfig().isDeleteTaxon()){
+                                   taxonService.saveOrUpdate(taxon);
+                                   saveOrUpdate(taxonNode);
+
+                                       TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
+                                       DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, classification.getUuid());
+                                       if (!resultTaxon.isOk()){
+                                result.addExceptions(resultTaxon.getExceptions());
+                                result.setStatus(resultTaxon.getStatus());
+                            }
+
+                               }
+                       }
+                       classification = null;
+
+                   } else {
+                       classification = null;
+                       Taxon taxon = taxonNode.getTaxon();
+                       taxon = HibernateProxyHelper.deproxy(taxon, Taxon.class);
+                       if (taxon != null){
+                               taxon.removeTaxonNode(taxonNode);
+                               if (config.getTaxonNodeConfig().isDeleteTaxon()){
+                                       TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
+                                       saveOrUpdate(taxonNode);
+                                       taxonService.saveOrUpdate(taxon);
+                                       DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, null);
+
+                            if (!resultTaxon.isOk()){
+                                result.addExceptions(resultTaxon.getExceptions());
+                                result.setStatus(resultTaxon.getStatus());
+                            }
+                               }
+                       }
+
+                   }
+
+                   result.addUpdatedObject(parent);
+                   if(result.getCdmEntity() == null){
+                       result.setCdmEntity(taxonNode);
+                }
+                   UUID uuid = dao.delete(taxonNode);
+                   logger.debug("Deleted node " +uuid.toString());
+
+               }
+        }
+        /*if (classification != null){
+            result.addUpdatedObject(classification);
+               DeleteResult resultClassification = classService.delete(classification);
+                if (!resultClassification.isOk()){
+                 result.addExceptions(resultClassification.getExceptions());
+                 result.setStatus(resultClassification.getStatus());
+             }
+        }*/
+        return result;
+
+    }
+
+
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult deleteTaxonNodes(Collection<UUID> nodeUuids, TaxonDeletionConfigurator config) {
+        List<TaxonNode> nodes = new ArrayList<TaxonNode>();
+        for(UUID nodeUuid : nodeUuids) {
+            nodes.add(dao.load(nodeUuid));
+        }
+        return deleteTaxonNodes(nodes, config);
+    }
+
+
+
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult deleteTaxonNode(UUID nodeUUID, TaxonDeletionConfigurator config) {
+
+       TaxonNode node = HibernateProxyHelper.deproxy(dao.load(nodeUUID), TaxonNode.class);
+       return deleteTaxonNode(node, config);
+    }
+
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult deleteTaxonNode(TaxonNode node, TaxonDeletionConfigurator config) {
+        DeleteResult result = new DeleteResult();
+        if (node == null){
+            result.setAbort();
+            result.addException(new Exception("The TaxonNode was already deleted."));
+            return result;
+        }
+        Taxon taxon = null;
+        try{
+            taxon = HibernateProxyHelper.deproxy(node.getTaxon());
+        }catch(NullPointerException e){
+            result.setAbort();
+            result.addException(new Exception("The Taxon was already deleted."));
+
+        }
+       TaxonNode parent = HibernateProxyHelper.deproxy(node.getParent(), TaxonNode.class);
+       if (config == null){
+               config = new TaxonDeletionConfigurator();
+       }
+
+
+
+       if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.MOVE_TO_PARENT)){
+          Object[] children = node.getChildNodes().toArray();
+          TaxonNode childNode;
+          for (Object child: children){
+              childNode = (TaxonNode) child;
+              parent.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference());
+          }
+       }else{
+           deleteTaxonNodes(node.getChildNodes(), config);
+       }
+
+       if (taxon != null){
+               if (config.getTaxonNodeConfig().isDeleteTaxon() && (config.isDeleteInAllClassifications() || taxon.getTaxonNodes().size() == 1)){
+                       result = taxonService.deleteTaxon(taxon.getUuid(), config, node.getClassification().getUuid());
+                       result.addUpdatedObject(parent);
+                       if (result.isOk()){
+                               return result;
+                       }
+               } else {
+                   result.addUpdatedObject(taxon);
+               }
+       }
+       result.setCdmEntity(node);
+       boolean success = taxon.removeTaxonNode(node);
+       dao.save(parent);
+       taxonService.saveOrUpdate(taxon);
+       result.addUpdatedObject(parent);
+
+       if (success){
+                       result.setStatus(Status.OK);
+                       parent = HibernateProxyHelper.deproxy(parent, TaxonNode.class);
+                       int index = parent.getChildNodes().indexOf(node);
+                       if (index > -1){
+                           parent.removeChild(index);
+                       }
+               if (!dao.delete(node, config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)).equals(null)){
+                       return result;
+               } else {
+                       result.setError();
+                       return result;
+               }
+       }else{
+           if (dao.findByUuid(node.getUuid()) != null){
+                       result.setError();
+                       result.addException(new Exception("The node can not be removed from the taxon."));
+               }
+               return result;
+       }
+
+
+
+    }
+
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#listAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification, int, int)
+     */
+    @Override
+    public List<TaxonNode> listAllNodesForClassification(Classification classification, Integer start, Integer end) {
+        return dao.getTaxonOfAcceptedTaxaByClassification(classification, start, end);
+    }
+
+    @Override
+    public int countAllNodesForClassification(Classification classification) {
+        return dao.countTaxonOfAcceptedTaxaByClassification(classification);
+    }
+
+    @Override
+    @Transactional
+    public UpdateResult moveTaxonNode(UUID taxonNodeUuid, UUID targetNodeUuid, int movingType){
+        TaxonNode taxonNode = HibernateProxyHelper.deproxy(dao.load(taxonNodeUuid), TaxonNode.class);
+       TaxonNode targetNode = HibernateProxyHelper.deproxy(dao.load(targetNodeUuid), TaxonNode.class);
+       return moveTaxonNode(taxonNode, targetNode, movingType);
+    }
+
+    @Override
+    @Transactional
+    public UpdateResult moveTaxonNode(TaxonNode taxonNode, TaxonNode newParent, int movingType){
+        UpdateResult result = new UpdateResult();
+
+        TaxonNode parentParent = HibernateProxyHelper.deproxy(newParent.getParent(), TaxonNode.class);
+
+        Integer sortIndex = -1;
+        if (movingType == 0){
+            sortIndex = 0;
+        }else if (movingType == 1){
+            sortIndex = newParent.getSortIndex();
+            newParent = parentParent;
+        } else if (movingType == 2){
+            sortIndex = newParent.getSortIndex() +1;
+            newParent = parentParent;
+        } else{
+            result.setAbort();
+            result.addException(new Exception("The moving type "+ movingType +" is not supported."));
+        }
+        result.addUpdatedObject(newParent);
+        result.addUpdatedObject(taxonNode.getParent());
+        result.setCdmEntity(taxonNode);
+
+        newParent.addChildNode(taxonNode, sortIndex, taxonNode.getReference(),  taxonNode.getMicroReference());
+
+        dao.saveOrUpdate(newParent);
+
+        return result;
+    }
+
+
+
+    @Override
+    @Transactional
+    public UpdateResult moveTaxonNodes(Set<UUID> taxonNodeUuids, UUID newParentNodeUuid, int movingType){
+        UpdateResult result = new UpdateResult();
+        TaxonNode targetNode = dao.load(newParentNodeUuid);
+        for (UUID taxonNodeUuid: taxonNodeUuids){
+            TaxonNode taxonNode = dao.load(taxonNodeUuid);
+            result.includeResult(moveTaxonNode(taxonNode,targetNode, movingType));
+        }
+        return result;
+    }
+
+    @Override
+    public Pager<TaxonNodeAgentRelation> pageTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,
+            UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
+
+
+        List<TaxonNodeAgentRelation> records = null;
+
+        long count = dao.countTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid);
+        if(PagerUtils.hasResultsInRange(count, pageIndex, pageSize)) {
+            records = dao.listTaxonNodeAgentRelations(taxonUuid, classificationUuid,
+                    agentUuid, rankUuid, relTypeUuid, PagerUtils.startFor(pageSize, pageIndex), PagerUtils.limitFor(pageSize), propertyPaths);
+        }
+
+        Pager<TaxonNodeAgentRelation> pager = new DefaultPagerImpl<TaxonNodeAgentRelation>(pageIndex, count, pageSize, records);
+        return pager;
+    }
+
+    @Override
+    @Transactional
+    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, Taxon newTaxon, Reference ref, String microref){
+        UpdateResult result = new UpdateResult();
+
+        UUID taxonUUID = taxonService.saveOrUpdate(newTaxon);
+        newTaxon = (Taxon) taxonService.load(taxonUUID);
+
+        TaxonNode parent = dao.load(parentNodeUuid);
+        TaxonNode child = null;
+        try{
+            child = parent.addChildTaxon(newTaxon, parent.getReference(), parent.getMicroReference());
+        }catch(Exception e){
+            result.addException(e);
+            result.setError();
+            return result;
+        }
+//        child = dao.save(child);
+
+        dao.saveOrUpdate(parent);
+        result.addUpdatedObject(parent);
+        if (child != null){
+            result.setCdmEntity(child);
+        }
+        return result;
+
+    }
+    @Override
+    @Transactional
+    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, UUID taxonUuid, Reference ref, String microref){
+        UpdateResult result = new UpdateResult();
+        TaxonNode parent = dao.load(parentNodeUuid);
+        Taxon taxon = (Taxon) taxonService.load(taxonUuid);
+        TaxonNode child = null;
+        try{
+            child = parent.addChildTaxon(taxon, parent.getReference(), parent.getMicroReference());
+        }catch(Exception e){
+            result.addException(e);
+            result.setError();
+            return result;
+        }
+//        child = dao.save(child);
+
+        dao.saveOrUpdate(parent);
+        result.addUpdatedObject(parent);
+        if (child != null){
+            result.setCdmEntity(child);
+        }
+        return result;
+
+    }
+
+    @Override
+    @Transactional
+    public UpdateResult addTaxonNodeAgentRelation(UUID taxonNodeUUID, UUID agentUUID, DefinedTerm relationshipType){
+        UpdateResult result = new UpdateResult();
+        TaxonNode node = dao.load(taxonNodeUUID);
+        TeamOrPersonBase agent = (TeamOrPersonBase) agentService.load(agentUUID);
+        node.addAgentRelation(relationshipType, agent);
+        try{
+            dao.merge(node, true);
+        }catch (Exception e){
+            result.setError();
+            result.addException(e);
+        }
+        result.setCdmEntity(node);
+        return result;
+    }
+
+
+}