fixed problem with deletion of nodes.
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonServiceImpl.java
index 221b7e7f6e416e1eb22d1ac718f0b8e23d85b415..ac291728973142b3775f5a7106d01605e2088169 100644 (file)
@@ -15,6 +15,7 @@ import java.util.ArrayList;
 import java.util.EnumSet;\r
 import java.util.HashMap;\r
 import java.util.HashSet;\r
+import java.util.Iterator;\r
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Set;\r
@@ -36,8 +37,9 @@ import org.springframework.transaction.annotation.Transactional;
 \r
 import eu.etaxonomy.cdm.api.service.config.IFindTaxaAndNamesConfigurator;\r
 import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;\r
-import eu.etaxonomy.cdm.api.service.config.NameDeletionConfigurator;\r
+import eu.etaxonomy.cdm.api.service.config.SynonymDeletionConfigurator;\r
 import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;\r
+import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator.ChildHandling;\r
 import eu.etaxonomy.cdm.api.service.exception.DataChangeNoRollbackException;\r
 import eu.etaxonomy.cdm.api.service.exception.HomotypicalGroupChangeException;\r
 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;\r
@@ -139,6 +141,10 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
     @Autowired\r
     private INameService nameService;\r
+    \r
+    @Autowired\r
+    private ITaxonNodeService nodeService;\r
+    \r
 \r
     @Autowired\r
     private ICdmGenericDao genericDao;\r
@@ -158,7 +164,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     @Autowired\r
     private ILuceneIndexToolProvider luceneIndexToolProvider;\r
 \r
-\r
     /**\r
      * Constructor\r
      */\r
@@ -270,11 +275,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)\r
      */\r
-    //TODO correct delete handling still needs to be implemented / checked\r
+    \r
     @Override\r
     @Transactional(readOnly = false)\r
     public Taxon changeSynonymToAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon, boolean deleteSynonym, boolean copyCitationInfo, Reference citation, String microCitation) throws HomotypicalGroupChangeException{\r
-\r
+       \r
         TaxonNameBase<?,?> acceptedName = acceptedTaxon.getName();\r
         TaxonNameBase<?,?> synonymName = synonym.getName();\r
         HomotypicalGroup synonymHomotypicGroup = synonymName.getHomotypicalGroup();\r
@@ -300,12 +305,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         }\r
 \r
         //synonym.getName().removeTaxonBase(synonym);\r
-        //TODO correct delete handling still needs to be implemented / checked\r
+       \r
         if (deleteSynonym){\r
 //                     deleteSynonym(synonym, taxon, false);\r
             try {\r
                 this.dao.flush();\r
-                this.delete(synonym);\r
+                this.deleteSynonym(synonym, acceptedTaxon, new SynonymDeletionConfigurator());\r
 \r
             } catch (Exception e) {\r
                 logger.info("Can't delete old synonym from database");\r
@@ -425,9 +430,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)\r
      */\r
     @Override\r
-    public Pager<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz,\r
-            String uninomial,  String infragenericEpithet, String specificEpithet,\r
-            String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {\r
+    public Pager<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String uninomial, String infragenericEpithet, String specificEpithet,     String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {\r
         Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);\r
 \r
         List<TaxonBase> results = new ArrayList<TaxonBase>();\r
@@ -438,7 +441,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return new DefaultPagerImpl<TaxonBase>(pageNumber, numberOfResults, pageSize, results);\r
     }\r
 \r
-\r
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)\r
      */\r
@@ -939,20 +941,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)\r
      */\r
     @Override\r
-    public void deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config) throws ReferencedObjectUndeletableException {\r
+    public UUID deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config, Classification classification) throws DataChangeNoRollbackException {\r
         if (config == null){\r
             config = new TaxonDeletionConfigurator();\r
         }\r
 \r
-            //         TaxonNode\r
-            if (! config.isDeleteTaxonNodes()){\r
-                if (taxon.getTaxonNodes().size() > 0){\r
-                    String message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";\r
-                    throw new ReferencedObjectUndeletableException(message);\r
-                }\r
-            }\r
-\r
-\r
             //         SynonymRelationShip\r
             if (config.isDeleteSynonymRelations()){\r
                 boolean removeSynonymNameFromHomotypicalGroup = false;\r
@@ -962,7 +955,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                     if (config.isDeleteSynonymsIfPossible()){\r
                         //TODO which value\r
                         boolean newHomotypicGroupIfNeeded = true;\r
-                        deleteSynonym(synonym, taxon, config.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded);\r
+                        SynonymDeletionConfigurator synConfig = new SynonymDeletionConfigurator();\r
+                        \r
+                        deleteSynonym(synonym, taxon, synConfig);\r
                     }else{\r
                         deleteSynonymRelationships(synonym, taxon);\r
                     }\r
@@ -975,73 +970,242 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                     String message = "Taxon can't be deleted as it is related to another taxon. Remove taxon from all relations to other taxa prior to deletion.";\r
                     throw new ReferencedObjectUndeletableException(message);\r
                 }\r
+            } else{\r
+               for (TaxonRelationship taxRel: taxon.getTaxonRelations()){\r
+                           \r
+                               \r
+                               \r
+                               if (config.isDeleteMisappliedNamesAndInvalidDesignations()){\r
+                                       if (taxRel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR()) || taxRel.getType().equals(TaxonRelationshipType.INVALID_DESIGNATION_FOR())){\r
+                                               if (taxon.equals(taxRel.getToTaxon())){\r
+                                                       this.deleteTaxon(taxRel.getFromTaxon(), config, classification);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               taxon.removeTaxonRelation(taxRel);\r
+                       /*if (taxFrom.equals(taxon)){\r
+                               try{\r
+                                       this.deleteTaxon(taxTo, taxConf, classification);\r
+                               } catch(DataChangeNoRollbackException e){\r
+                                       logger.debug("A related taxon will not be deleted." + e.getMessage());\r
+                               }\r
+                       } else {\r
+                               try{\r
+                                       this.deleteTaxon(taxFrom, taxConf, classification);\r
+                               } catch(DataChangeNoRollbackException e){\r
+                                       logger.debug("A related taxon will not be deleted." + e.getMessage());\r
+                               }\r
+                               \r
+                       }*/\r
+               }\r
             }\r
 \r
 \r
+            \r
+                   \r
             //         TaxonDescription\r
+            if (config.isDeleteDescriptions()){\r
                     Set<TaxonDescription> descriptions = taxon.getDescriptions();\r
 \r
                     for (TaxonDescription desc: descriptions){\r
-                        if (config.isDeleteDescriptions()){\r
-                            //TODO use description delete configurator ?\r
-                            //FIXME check if description is ALWAYS deletable\r
-                            descriptionService.delete(desc);\r
-                        }else{\r
-                            if (desc.getDescribedSpecimenOrObservation() != null){\r
-                                String message = "Taxon can't be deleted as it is used in a TaxonDescription" +\r
-                                        " which also describes specimens or abservations";\r
-                                    throw new ReferencedObjectUndeletableException(message);\r
-                                }\r
-                            }\r
+                        //TODO use description delete configurator ?\r
+                        //FIXME check if description is ALWAYS deletable\r
+                       if (desc.getDescribedSpecimenOrObservation() != null){\r
+                               String message = "Taxon can't be deleted as it is used in a TaxonDescription" +\r
+                                               " which also describes specimens or abservations";\r
+                            throw new ReferencedObjectUndeletableException(message);\r
                         }\r
+                        descriptionService.delete(desc);\r
+                        taxon.removeDescription(desc);\r
+                    }\r
+            }\r
 \r
 \r
-                //check references with only reverse mapping\r
-            Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(taxon);\r
-            for (CdmBase referencingObject : referencingObjects){\r
-                //IIdentificationKeys (Media, Polytomous, MultiAccess)\r
-                if (HibernateProxyHelper.isInstanceOf(referencingObject, IIdentificationKey.class)){\r
-                    String message = "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";\r
-                    message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnit.class).getTitleCache());\r
-                    throw new ReferencedObjectUndeletableException(message);\r
-                }\r
-\r
-\r
-                //PolytomousKeyNode\r
-                if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){\r
-                    String message = "Taxon can't be deleted as it is used in polytomous key node";\r
-                    throw new ReferencedObjectUndeletableException(message);\r
-                }\r
-\r
-                //TaxonInteraction\r
-                if (referencingObject.isInstanceOf(TaxonInteraction.class)){\r
-                    String message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2";\r
+            //check references with only reverse mapping\r
+        String message = checkForReferences(taxon);\r
+               if (message != null){\r
+                       throw new ReferencedObjectUndeletableException(message.toString());\r
+               }\r
+                \r
+                if (! config.isDeleteTaxonNodes() || (!config.isDeleteInAllClassifications() && classification == null )){\r
+                if (taxon.getTaxonNodes().size() > 0){\r
+                    message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion or define a classification where it should be deleted or adapt the taxon deletion configurator.";\r
                     throw new ReferencedObjectUndeletableException(message);\r
                 }\r
+            }else{\r
+               if (taxon.getTaxonNodes().size() != 0){\r
+                       Set<TaxonNode> nodes = taxon.getTaxonNodes();\r
+                       Iterator<TaxonNode> iterator = nodes.iterator();\r
+                       TaxonNode node = null;\r
+                       boolean deleteChildren;\r
+                               if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)){\r
+                                       deleteChildren = true;\r
+                               }else {\r
+                                       deleteChildren = false;\r
+                               }\r
+                               boolean success = true;\r
+                       if (!config.isDeleteInAllClassifications() && !(classification == null)){\r
+                               while (iterator.hasNext()){\r
+                                       node = iterator.next();\r
+                                       if (node.getClassification().equals(classification)){\r
+                                               break;\r
+                                       }\r
+                                       node = null;\r
+                               }\r
+                               if (node != null){\r
+                                       success =taxon.removeTaxonNode(node, deleteChildren);\r
+                               } else {\r
+                                       message = "Taxon is not used in defined classification";\r
+                                       throw new DataChangeNoRollbackException(message);\r
+                               }\r
+                       } else if (config.isDeleteInAllClassifications()){\r
+                               List<TaxonNode> nodesList = new ArrayList<TaxonNode>();\r
+                               nodesList.addAll(taxon.getTaxonNodes());\r
+                               \r
+                                       for (TaxonNode taxonNode: nodesList){\r
+                                               if(deleteChildren){\r
+                                                       Object[] childNodes = taxonNode.getChildNodes().toArray();\r
+                                                       for (Object childNode: childNodes){\r
+                                                               TaxonNode childNodeCast = (TaxonNode) childNode;\r
+                                                               deleteTaxon(childNodeCast.getTaxon(), config, classification);\r
+                                                               \r
+                                                       }\r
+                                                       \r
+                                                       /*for (TaxonNode childNode: taxonNode.getChildNodes()){\r
+                                                               deleteTaxon(childNode.getTaxon(), config, classification);\r
+                                                               \r
+                                                       }*/\r
+                                                       //taxon.removeTaxonNode(taxonNode);\r
+                                               } else{\r
+                                                       Object[] childNodes = taxonNode.getChildNodes().toArray();\r
+                                                       for (Object childNode: childNodes){\r
+                                                               TaxonNode childNodeCast = (TaxonNode) childNode;\r
+                                                               taxonNode.getParent().addChildNode(childNodeCast, childNodeCast.getReference(), childNodeCast.getMicroReference());\r
+                                                       }\r
+                                                       \r
+                                                       //taxon.removeTaxonNode(taxonNode);\r
+                                               }\r
+                                       }\r
+                               \r
+                               \r
+                               \r
+                               nodeService.deleteTaxonNodes(nodesList);\r
+                               \r
+                       }\r
+                       if (!success){\r
+                                message = "The taxon node could not be deleted.";\r
+                               throw new DataChangeNoRollbackException(message);\r
+                       }\r
+               }\r
             }\r
-\r
-\r
             //TaxonNameBase\r
             if (config.isDeleteNameIfPossible()){\r
                 try {\r
-                    nameService.delete(taxon.getName(), config.getNameDeletionConfig());\r
+                       \r
+                       //TaxonNameBase name = nameService.find(taxon.getName().getUuid());\r
+                       TaxonNameBase name = (TaxonNameBase)HibernateProxyHelper.deproxy(taxon.getName());\r
+                       //check whether taxon will be deleted or not\r
+                       if (taxon.getTaxonNodes() == null || taxon.getTaxonNodes().size()== 0){\r
+                               taxon = (Taxon) HibernateProxyHelper.deproxy(taxon);\r
+                               name.removeTaxonBase(taxon);\r
+                           nameService.save(name);\r
+                               nameService.delete(name, config.getNameDeletionConfig());\r
+                       }\r
                 } catch (ReferencedObjectUndeletableException e) {\r
                     //do nothing\r
                     if (logger.isDebugEnabled()){logger.debug("Name could not be deleted");}\r
+                    \r
                 }\r
             }\r
-\r
+            \r
+//             TaxonDescription\r
+           /* Set<TaxonDescription> descriptions = taxon.getDescriptions();\r
+\r
+            for (TaxonDescription desc: descriptions){\r
+                if (config.isDeleteDescriptions()){\r
+                    //TODO use description delete configurator ?\r
+                    //FIXME check if description is ALWAYS deletable\r
+                       taxon.removeDescription(desc);\r
+                    descriptionService.delete(desc);\r
+                }else{\r
+                    if (desc.getDescribedSpecimenOrObservations().size()>0){\r
+                        String message = "Taxon can't be deleted as it is used in a TaxonDescription" +\r
+                                " which also describes specimens or observations";\r
+                            throw new ReferencedObjectUndeletableException(message);\r
     }\r
+                    }\r
+                }*/\r
+            \r
+           \r
+\r
+            if (taxon.getTaxonNodes() == null || taxon.getTaxonNodes().size()== 0){\r
+               dao.delete(taxon);\r
+               return taxon.getUuid();\r
+            } else{\r
+               message = "Taxon can't be deleted as it is used in another Taxonnode";\r
+               throw new ReferencedObjectUndeletableException(message);\r
+            }\r
+            \r
+\r
+    }\r
+    \r
+    private String checkForReferences(Taxon taxon){\r
+       Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(taxon);\r
+        for (CdmBase referencingObject : referencingObjects){\r
+            //IIdentificationKeys (Media, Polytomous, MultiAccess)\r
+            if (HibernateProxyHelper.isInstanceOf(referencingObject, IIdentificationKey.class)){\r
+                String message = "Taxon" + taxon.getTitleCache() + "can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";\r
+              \r
+                return message;\r
+            }\r
+\r
+\r
+            //PolytomousKeyNode\r
+            if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){\r
+                String message = "Taxon" + taxon.getTitleCache() + " can't be deleted as it is used in polytomous key node";\r
+                return message;\r
+            }\r
 \r
+            //TaxonInteraction\r
+            if (referencingObject.isInstanceOf(TaxonInteraction.class)){\r
+                String message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2";\r
+                return message;\r
+            }\r
+        }\r
+        referencingObjects = null;\r
+        return null;\r
+    }\r
+    \r
+    @Transactional(readOnly = false)\r
+    public UUID delete(Synonym syn){\r
+       UUID result = syn.getUuid();\r
+       this.deleteSynonym(syn, null);\r
+       return result;\r
+    }\r
+    \r
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)\r
      */\r
     @Transactional(readOnly = false)\r
     @Override\r
-    public void deleteSynonym(Synonym synonym, Taxon taxon, boolean removeNameIfPossible,boolean newHomotypicGroupIfNeeded) {\r
+       public void deleteSynonym(Synonym synonym, SynonymDeletionConfigurator config) {\r
+       deleteSynonym(synonym, null, config);\r
+               \r
+       }\r
+    \r
+\r
+       /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)\r
+     */\r
+    @Transactional(readOnly = false)\r
+    @Override\r
+    public void deleteSynonym(Synonym synonym, Taxon taxon, SynonymDeletionConfigurator config) {\r
         if (synonym == null){\r
             return;\r
         }\r
+        if (config == null){\r
+               config = new SynonymDeletionConfigurator();\r
+        }\r
         synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);\r
 \r
         //remove synonymRelationship\r
@@ -1053,23 +1217,26 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         }\r
         for (Taxon relatedTaxon : taxonSet){\r
 //                     dao.deleteSynonymRelationships(synonym, relatedTaxon);\r
-            relatedTaxon.removeSynonym(synonym, newHomotypicGroupIfNeeded);\r
+            relatedTaxon.removeSynonym(synonym, config.isNewHomotypicGroupIfNeeded());\r
         }\r
         this.saveOrUpdate(synonym);\r
 \r
         //TODO remove name from homotypical group?\r
 \r
         //remove synonym (if necessary)\r
+        \r
+        \r
         if (synonym.getSynonymRelations().isEmpty()){\r
             TaxonNameBase<?,?> name = synonym.getName();\r
             synonym.setName(null);\r
             dao.delete(synonym);\r
 \r
             //remove name if possible (and required)\r
-            if (name != null && removeNameIfPossible){\r
+            if (name != null && config.isDeleteNameIfPossible()){\r
                 try{\r
-                    nameService.delete(name, new NameDeletionConfigurator());\r
-                }catch (DataChangeNoRollbackException ex){\r
+                    nameService.delete(name, config.getNameDeletionConfig());\r
+                }catch (ReferencedObjectUndeletableException ex){\r
+                       System.err.println("Name wasn't deleted as it is referenced");\r
                     if (logger.isDebugEnabled()) {\r
                         logger.debug("Name wasn't deleted as it is referenced");\r
                     }\r
@@ -2521,8 +2688,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         Reference<?> sourceReference = syn.getSec();\r
 \r
         if (sourceReference == null){\r
-            logger.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon.getSec());\r
-            sourceReference = taxon.getSec();\r
+                logger.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon.getSec());\r
+             sourceReference = taxon.getSec();\r
         }\r
 \r
         synName = syn.getName();\r