merge-update from trunk
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonServiceImpl.java
index b8c4f5e5f54e3f8acf4075b351cd5cb3f1ca53f8..dcb0b8f27907c7f3b87a3338218bef84210690a9 100644 (file)
@@ -39,10 +39,12 @@ import org.springframework.transaction.annotation.Transactional;
 \r
 import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;\r
 import eu.etaxonomy.cdm.api.service.config.IFindTaxaAndNamesConfigurator;\r
 \r
 import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;\r
 import eu.etaxonomy.cdm.api.service.config.IFindTaxaAndNamesConfigurator;\r
+import eu.etaxonomy.cdm.api.service.config.IncludedTaxonConfiguration;\r
 import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;\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.config.MatchingTaxonConfigurator;\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.dto.IncludedTaxaDTO;\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
 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
@@ -189,28 +191,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return dao.getTaxaByName(name, sec);\r
     }\r
 \r
         return dao.getTaxaByName(name, sec);\r
     }\r
 \r
-    /**\r
-     * FIXME Candidate for harmonization\r
-     * list(Synonym.class, ...)\r
-     *  (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)\r
-     */\r
-    @Override\r
-    public List<Synonym> getAllSynonyms(int limit, int start) {\r
-        return dao.getAllSynonyms(limit, start);\r
-    }\r
-\r
-    /**\r
-     * FIXME Candidate for harmonization\r
-     * list(Taxon.class, ...)\r
-     *  (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)\r
-     */\r
-    @Override\r
-    public List<Taxon> getAllTaxa(int limit, int start) {\r
-        return dao.getAllTaxa(limit, start);\r
-    }\r
-\r
     /**\r
      * FIXME Candidate for harmonization\r
      * merge with getRootTaxa(Reference sec, ..., ...)\r
     /**\r
      * FIXME Candidate for harmonization\r
      * merge with getRootTaxa(Reference sec, ..., ...)\r
@@ -225,18 +205,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return dao.getRootTaxa(sec, cdmFetch, onlyWithChildren, false);\r
     }\r
 \r
         return dao.getRootTaxa(sec, cdmFetch, onlyWithChildren, false);\r
     }\r
 \r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)\r
-     */\r
     @Override\r
     public List<Taxon> getRootTaxa(Rank rank, Reference sec, boolean onlyWithChildren,boolean withMisapplications, List<String> propertyPaths) {\r
         return dao.getRootTaxa(rank, sec, null, onlyWithChildren, withMisapplications, propertyPaths);\r
     }\r
 \r
     @Override\r
     public List<Taxon> getRootTaxa(Rank rank, Reference sec, boolean onlyWithChildren,boolean withMisapplications, List<String> propertyPaths) {\r
         return dao.getRootTaxa(rank, sec, null, onlyWithChildren, withMisapplications, propertyPaths);\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)\r
-     */\r
     @Override\r
     public List<RelationshipBase> getAllRelationships(int limit, int start){\r
         return dao.getAllRelationships(limit, start);\r
     @Override\r
     public List<RelationshipBase> getAllRelationships(int limit, int start){\r
         return dao.getAllRelationships(limit, start);\r
@@ -819,10 +792,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 numberTaxaResults = dao.countTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());\r
             }\r
             if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){\r
                 numberTaxaResults = dao.countTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());\r
             }\r
             if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){\r
-                List<Object[]> commonNameResults = dao.getTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas(), configurator.getPageSize(), configurator.getPageNumber(), configurator.getTaxonPropertyPath());\r
-                for( Object[] entry : commonNameResults ) {\r
-                    taxa.add((TaxonBase) entry[0]);\r
-                }\r
+                List<Taxon> commonNameResults = dao.getTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas(), configurator.getPageSize(), configurator.getPageNumber(), configurator.getTaxonPropertyPath());\r
+                taxa.addAll(commonNameResults);\r
             }\r
             if(taxa != null){\r
                 results.addAll(taxa);\r
             }\r
             if(taxa != null){\r
                 results.addAll(taxa);\r
@@ -882,6 +853,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         Set<Taxon> taxa = new HashSet<Taxon>();\r
         List<Media> taxonMedia = new ArrayList<Media>();\r
 \r
         Set<Taxon> taxa = new HashSet<Taxon>();\r
         List<Media> taxonMedia = new ArrayList<Media>();\r
+        List<Media> nonImageGalleryImages = new ArrayList<Media>();\r
 \r
         if (limitToGalleries == null) {\r
             limitToGalleries = false;\r
 \r
         if (limitToGalleries == null) {\r
             limitToGalleries = false;\r
@@ -906,11 +878,18 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 if (!limitToGalleries || taxonDescription.isImageGallery()) {\r
                     for (DescriptionElementBase element : taxonDescription.getElements()) {\r
                         for (Media media : element.getMedia()) {\r
                 if (!limitToGalleries || taxonDescription.isImageGallery()) {\r
                     for (DescriptionElementBase element : taxonDescription.getElements()) {\r
                         for (Media media : element.getMedia()) {\r
-                            taxonMedia.add(media);\r
+                            if(taxonDescription.isImageGallery()){\r
+                                taxonMedia.add(media);\r
+                            }\r
+                            else{\r
+                                nonImageGalleryImages.add(media);\r
+                            }\r
                         }\r
                     }\r
                 }\r
             }\r
                         }\r
                     }\r
                 }\r
             }\r
+            //put images from image gallery first (#3242)\r
+            taxonMedia.addAll(nonImageGalleryImages);\r
         }\r
 \r
 \r
         }\r
 \r
 \r
@@ -1036,13 +1015,14 @@ 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
      * @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 String deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config, Classification classification)  {\r
-        if (config == null){\r
+    public DeleteResult deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config, Classification classification)  {\r
+       DeleteResult result = new DeleteResult();\r
+       if (config == null){\r
             config = new TaxonDeletionConfigurator();\r
         }\r
             config = new TaxonDeletionConfigurator();\r
         }\r
-        \r
+\r
         List<String> referencedObjects = isDeletable(taxon, config);\r
         List<String> referencedObjects = isDeletable(taxon, config);\r
-        \r
+\r
         if (referencedObjects.isEmpty()){\r
             // --- DeleteSynonymRelations\r
             if (config.isDeleteSynonymRelations()){\r
         if (referencedObjects.isEmpty()){\r
             // --- DeleteSynonymRelations\r
             if (config.isDeleteSynonymRelations()){\r
@@ -1164,8 +1144,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                             success =taxon.removeTaxonNode(node, deleteChildren);\r
                             nodeService.delete(node);\r
                         } else {\r
                             success =taxon.removeTaxonNode(node, deleteChildren);\r
                             nodeService.delete(node);\r
                         } else {\r
-                           // message = "Taxon is not used in defined classification";\r
-                           // throw new DataChangeNoRollbackException(message);\r
+                               result.setError();\r
+                               result.addException(new Exception("The taxon can not be deleted because it is not used in defined classification."));\r
                         }\r
                     } else if (config.isDeleteInAllClassifications()){\r
                         Set<ITaxonTreeNode> nodesList = new HashSet<ITaxonTreeNode>();\r
                         }\r
                     } else if (config.isDeleteInAllClassifications()){\r
                         Set<ITaxonTreeNode> nodesList = new HashSet<ITaxonTreeNode>();\r
@@ -1200,11 +1180,15 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                                 }\r
                             }\r
                         config.getTaxonNodeConfig().setDeleteTaxon(false);\r
                                 }\r
                             }\r
                         config.getTaxonNodeConfig().setDeleteTaxon(false);\r
-                        nodeService.deleteTaxonNodes(nodesList, config);\r
+                        DeleteResult resultNodes = nodeService.deleteTaxonNodes(nodesList, config);\r
+                        if (!resultNodes.isOk()){\r
+                               result.addExceptions(resultNodes.getExceptions());\r
+                               result.setStatus(resultNodes.getStatus());\r
+                        }\r
                     }\r
                     if (!success){\r
                     }\r
                     if (!success){\r
-                        // message = "The taxon node could not be deleted.";\r
-                        //throw new DataChangeNoRollbackException(message);\r
+                        result.setError();\r
+                        result.addException(new Exception("The taxon can not be deleted because the taxon node can not be removed."));\r
                     }\r
                 }\r
             }\r
                     }\r
                 }\r
             }\r
@@ -1212,10 +1196,10 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
              //PolytomousKey TODO\r
 \r
 \r
              //PolytomousKey TODO\r
 \r
-             boolean usedInPolytomousKey = checkForPolytomousKeys(taxon);\r
+\r
             //TaxonNameBase\r
             if (config.isDeleteNameIfPossible()){\r
             //TaxonNameBase\r
             if (config.isDeleteNameIfPossible()){\r
-                \r
+\r
 \r
                     //TaxonNameBase name = nameService.find(taxon.getName().getUuid());\r
                     TaxonNameBase name = (TaxonNameBase)HibernateProxyHelper.deproxy(taxon.getName());\r
 \r
                     //TaxonNameBase name = nameService.find(taxon.getName().getUuid());\r
                     TaxonNameBase name = (TaxonNameBase)HibernateProxyHelper.deproxy(taxon.getName());\r
@@ -1223,11 +1207,19 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                     if ((taxon.getTaxonNodes() == null || taxon.getTaxonNodes().size()== 0) && name != null ){\r
                         taxon = (Taxon) HibernateProxyHelper.deproxy(taxon);\r
                         name.removeTaxonBase(taxon);\r
                     if ((taxon.getTaxonNodes() == null || taxon.getTaxonNodes().size()== 0) && name != null ){\r
                         taxon = (Taxon) HibernateProxyHelper.deproxy(taxon);\r
                         name.removeTaxonBase(taxon);\r
-                        nameService.save(name);\r
-                        String uuidString = nameService.delete(name, config.getNameDeletionConfig());\r
-                        logger.debug(uuidString);\r
+                        nameService.saveOrUpdate(name);\r
+                        DeleteResult nameResult = new DeleteResult();\r
+\r
+                        nameResult = nameService.delete(name, config.getNameDeletionConfig());\r
+\r
+                        if (nameResult.isError()){\r
+                               //result.setError();\r
+                               result.addRelatedObject(name);\r
+                               result.addExceptions(nameResult.getExceptions());\r
+                        }\r
+\r
                     }\r
                     }\r
-                \r
+\r
             }\r
 \r
 //             TaxonDescription\r
             }\r
 \r
 //             TaxonDescription\r
@@ -1247,17 +1239,32 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     }\r
                     }\r
                 }*/\r
     }\r
                     }\r
                 }*/\r
-        \r
+\r
             if ((taxon.getTaxonNodes() == null || taxon.getTaxonNodes().size()== 0)  ){\r
             if ((taxon.getTaxonNodes() == null || taxon.getTaxonNodes().size()== 0)  ){\r
-                UUID uuid = dao.delete(taxon);\r
-                return uuid.toString();\r
+               try{\r
+                       UUID uuid = dao.delete(taxon);\r
+\r
+               }catch(Exception e){\r
+                       result.addException(e);\r
+                       result.setError();\r
+\r
+               }\r
             } else {\r
             } else {\r
-               return "The Taxon can't be deleted.";\r
+               result.setError();\r
+               result.addException(new Exception("The Taxon can't be deleted."));\r
+\r
             }\r
         }else {\r
             }\r
         }else {\r
-                return referencedObjects.toString();\r
-        }\r
+               List<Exception> exceptions = new ArrayList<Exception>();\r
+               for (String message: referencedObjects){\r
+                       ReferencedObjectUndeletableException exception = new ReferencedObjectUndeletableException(message);\r
+                       exceptions.add(exception);\r
+               }\r
+               result.addExceptions(exceptions);\r
+               result.setError();\r
 \r
 \r
+        }\r
+        return result;\r
 \r
     }\r
 \r
 \r
     }\r
 \r
@@ -1312,12 +1319,14 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return result;\r
     }\r
 \r
         return result;\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
     /* (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 String deleteSynonym(Synonym synonym, SynonymDeletionConfigurator config) {\r
+    public DeleteResult deleteSynonym(Synonym synonym, SynonymDeletionConfigurator config) {\r
         return deleteSynonym(synonym, null, config);\r
 \r
     }\r
         return deleteSynonym(synonym, null, config);\r
 \r
     }\r
@@ -1328,57 +1337,70 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      */\r
     @Transactional(readOnly = false)\r
     @Override\r
      */\r
     @Transactional(readOnly = false)\r
     @Override\r
-    public String deleteSynonym(Synonym synonym, Taxon taxon, SynonymDeletionConfigurator config) {\r
-        if (synonym == null){\r
-            return null;\r
+    public DeleteResult deleteSynonym(Synonym synonym, Taxon taxon, SynonymDeletionConfigurator config) {\r
+        DeleteResult result = new DeleteResult();\r
+       if (synonym == null){\r
+               result.setAbort();\r
+               return result;\r
         }\r
         }\r
-        \r
+\r
         if (config == null){\r
             config = new SynonymDeletionConfigurator();\r
         }\r
         List<String> messages = isDeletable(synonym, config);\r
         if (config == null){\r
             config = new SynonymDeletionConfigurator();\r
         }\r
         List<String> messages = isDeletable(synonym, config);\r
+\r
+\r
         if (messages.isEmpty()){\r
         if (messages.isEmpty()){\r
-               synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);\r
-       \r
-               //remove synonymRelationship\r
-               Set<Taxon> taxonSet = new HashSet<Taxon>();\r
-               if (taxon != null){\r
-                   taxonSet.add(taxon);\r
-               }else{\r
-                   taxonSet.addAll(synonym.getAcceptedTaxa());\r
-               }\r
-               for (Taxon relatedTaxon : taxonSet){\r
-       //                      dao.deleteSynonymRelationships(synonym, relatedTaxon);\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
-               UUID uuid = null;\r
-               if (synonym.getSynonymRelations().isEmpty()){\r
-                   TaxonNameBase<?,?> name = synonym.getName();\r
-                   synonym.setName(null);\r
-                   uuid = dao.delete(synonym);\r
-       \r
-                   //remove name if possible (and required)\r
-                   if (name != null && config.isDeleteNameIfPossible()){\r
-                       \r
-                           nameService.delete(name, config.getNameDeletionConfig());\r
-                       \r
-                   }\r
-                   \r
-               }else {\r
-                       return null;\r
-               }\r
-               return uuid.toString();\r
+            synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);\r
+\r
+            //remove synonymRelationship\r
+            Set<Taxon> taxonSet = new HashSet<Taxon>();\r
+            if (taxon != null){\r
+                taxonSet.add(taxon);\r
+            }else{\r
+                taxonSet.addAll(synonym.getAcceptedTaxa());\r
+            }\r
+            for (Taxon relatedTaxon : taxonSet){\r
+    //                 dao.deleteSynonymRelationships(synonym, relatedTaxon);\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
+            UUID uuid = null;\r
+            if (synonym.getSynonymRelations().isEmpty()){\r
+                TaxonNameBase<?,?> name = synonym.getName();\r
+                synonym.setName(null);\r
+                uuid = dao.delete(synonym);\r
+\r
+                //remove name if possible (and required)\r
+                if (name != null && config.isDeleteNameIfPossible()){\r
+\r
+                        nameService.delete(name, config.getNameDeletionConfig());\r
+\r
+                }\r
+\r
+            }else {\r
+               result.setError();\r
+               result.addException(new ReferencedObjectUndeletableException("Synonym can not be deleted it is used in a synonymRelationship."));\r
+                return result;\r
+            }\r
+\r
+            return result;\r
         }else{\r
         }else{\r
-               return messages.toString();\r
+               List<Exception> exceptions = new ArrayList<Exception>();\r
+               for (String message :messages){\r
+                       exceptions.add(new ReferencedObjectUndeletableException(message));\r
+               }\r
+               result.setError();\r
+               result.addExceptions(exceptions);\r
+            return result;\r
         }\r
         }\r
-        \r
-     \r
+\r
+\r
     }\r
 \r
 \r
     }\r
 \r
 \r
@@ -2743,8 +2765,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             potentialCombination.addSource(originalSource);\r
         }\r
 \r
             potentialCombination.addSource(originalSource);\r
         }\r
 \r
-        inferredSynName.generateTitle();\r
-\r
         return potentialCombination;\r
     }\r
 \r
         return potentialCombination;\r
     }\r
 \r
@@ -2823,9 +2843,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_GENUS_OF());\r
 \r
 \r
         taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_GENUS_OF());\r
 \r
-        inferredSynName.generateTitle();\r
-\r
-\r
         return inferredGenus;\r
     }\r
 \r
         return inferredGenus;\r
     }\r
 \r
@@ -2920,7 +2937,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_EPITHET_OF());\r
 \r
 \r
         taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_EPITHET_OF());\r
 \r
-        inferredSynName.generateTitle();\r
         return inferredEpithet;\r
     }\r
 \r
         return inferredEpithet;\r
     }\r
 \r
@@ -3000,9 +3016,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return inferredSynonyms;\r
     }\r
 \r
         return inferredSynonyms;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listClassifications(eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)\r
-     */\r
     @Override\r
     public List<Classification> listClassifications(TaxonBase taxonBase, Integer limit, Integer start, List<String> propertyPaths) {\r
 \r
     @Override\r
     public List<Classification> listClassifications(TaxonBase taxonBase, Integer limit, Integer start, List<String> propertyPaths) {\r
 \r
@@ -3055,72 +3068,74 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
                 this.saveOrUpdate(toTaxon);\r
                 //TODO: configurator and classification\r
 \r
                 this.saveOrUpdate(toTaxon);\r
                 //TODO: configurator and classification\r
-                this.deleteTaxon(fromTaxon, null, null);\r
+                TaxonDeletionConfigurator config = new TaxonDeletionConfigurator();\r
+                config.setDeleteNameIfPossible(false);\r
+                this.deleteTaxon(fromTaxon, config, null);\r
                 return synonymRelationship.getSynonym();\r
 \r
     }\r
     @Override\r
     public List<String> isDeletable(TaxonBase taxonBase, DeleteConfiguratorBase config){\r
                 return synonymRelationship.getSynonym();\r
 \r
     }\r
     @Override\r
     public List<String> isDeletable(TaxonBase taxonBase, DeleteConfiguratorBase config){\r
-       List<String> result = new ArrayList<String>();\r
-       Set<CdmBase> references = commonService.getReferencingObjects(taxonBase);\r
-       if (taxonBase instanceof Taxon){\r
-               TaxonDeletionConfigurator taxonConfig = (TaxonDeletionConfigurator) config;\r
-               result = isDeletableForTaxon(references, taxonConfig);\r
-       }else{\r
-               SynonymDeletionConfigurator synonymConfig = (SynonymDeletionConfigurator) config;\r
-               result = isDeletableForSynonym(references, synonymConfig);\r
-       }\r
-       return result;\r
-    }\r
-    \r
+        List<String> result = new ArrayList<String>();\r
+        Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(taxonBase);\r
+        if (taxonBase instanceof Taxon){\r
+            TaxonDeletionConfigurator taxonConfig = (TaxonDeletionConfigurator) config;\r
+            result = isDeletableForTaxon(references, taxonConfig);\r
+        }else{\r
+            SynonymDeletionConfigurator synonymConfig = (SynonymDeletionConfigurator) config;\r
+            result = isDeletableForSynonym(references, synonymConfig);\r
+        }\r
+        return result;\r
+    }\r
+\r
     private List<String> isDeletableForSynonym(Set<CdmBase> references, SynonymDeletionConfigurator config){\r
     private List<String> isDeletableForSynonym(Set<CdmBase> references, SynonymDeletionConfigurator config){\r
-       String message;\r
-       List<String> result = new ArrayList<String>();\r
-       for (CdmBase ref: references){\r
-               if (!(ref instanceof SynonymRelationship || ref instanceof Taxon || ref instanceof TaxonNameBase)){\r
-                       message = "The Synonym can't be deleted as long as it is referenced by " + ref.getClass().getSimpleName() + " with id "+ ref.getId();\r
-                       result.add(message);\r
-               }\r
-       }\r
-       \r
-       return result;\r
+        String message;\r
+        List<String> result = new ArrayList<String>();\r
+        for (CdmBase ref: references){\r
+            if (!(ref instanceof SynonymRelationship || ref instanceof Taxon || ref instanceof TaxonNameBase )){\r
+                message = "The Synonym can't be deleted as long as it is referenced by " + ref.getClass().getSimpleName() + " with id "+ ref.getId();\r
+                result.add(message);\r
+            }\r
+        }\r
+\r
+        return result;\r
     }\r
     private List<String> isDeletableForTaxon(Set<CdmBase> references, TaxonDeletionConfigurator config){\r
     }\r
     private List<String> isDeletableForTaxon(Set<CdmBase> references, TaxonDeletionConfigurator config){\r
-       String message;\r
-       List<String> result = new ArrayList<String>();\r
-       for (CdmBase ref: references){\r
-               if (!(ref instanceof TaxonNameBase)){\r
-                       if (!config.isDeleteSynonymRelations() && (ref instanceof SynonymRelationship)){\r
-                               message = "The Taxon can't be deleted as long as it has synonyms.";\r
-                               result.add(message);\r
-                       }\r
-                       if (!config.isDeleteDescriptions() && (ref instanceof DescriptionBase)){\r
-                               message = "The Taxon can't be deleted as long as it has factual data.";\r
-                               result.add(message);\r
-                       }\r
-                       \r
-                       if (!config.isDeleteTaxonNodes() && (ref instanceof TaxonNode)){\r
-                               message = "The Taxon can't be deleted as long as it belongs to a taxon node.";\r
-                               result.add(message);\r
-                       }\r
-                       if (!config.isDeleteTaxonRelationships() && (ref instanceof TaxonNode)){\r
-                               if (!config.isDeleteMisappliedNamesAndInvalidDesignations() && (((TaxonRelationship)ref).getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())|| ((TaxonRelationship)ref).getType().equals(TaxonRelationshipType.INVALID_DESIGNATION_FOR()))){\r
-                                       message = "The Taxon can't be deleted as long as it has misapplied names or invalid designations.";\r
-                                       result.add(message);\r
-                               } else{\r
-                                       message = "The Taxon can't be deleted as long as it belongs to a taxon node.";\r
-                                       result.add(message);\r
-                               }\r
-                       }\r
-                       if (ref instanceof PolytomousKeyNode){\r
-                               message = "The Taxon can't be deleted as long as it is referenced by a polytomous key node.";\r
-                               result.add(message);\r
-                       }\r
-                       \r
-                       if (HibernateProxyHelper.isInstanceOf(ref, IIdentificationKey.class)){\r
+        String message;\r
+        List<String> result = new ArrayList<String>();\r
+        for (CdmBase ref: references){\r
+            if (!(ref instanceof TaxonNameBase)){\r
+                if (!config.isDeleteSynonymRelations() && (ref instanceof SynonymRelationship)){\r
+                    message = "The Taxon can't be deleted as long as it has synonyms.";\r
+                    result.add(message);\r
+                }\r
+                if (!config.isDeleteDescriptions() && (ref instanceof DescriptionBase)){\r
+                    message = "The Taxon can't be deleted as long as it has factual data.";\r
+                    result.add(message);\r
+                }\r
+\r
+                if (!config.isDeleteTaxonNodes() && (ref instanceof TaxonNode)){\r
+                    message = "The Taxon can't be deleted as long as it belongs to a taxon node.";\r
+                    result.add(message);\r
+                }\r
+                if (!config.isDeleteTaxonRelationships() && (ref instanceof TaxonNode)){\r
+                    if (!config.isDeleteMisappliedNamesAndInvalidDesignations() && (((TaxonRelationship)ref).getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())|| ((TaxonRelationship)ref).getType().equals(TaxonRelationshipType.INVALID_DESIGNATION_FOR()))){\r
+                        message = "The Taxon can't be deleted as long as it has misapplied names or invalid designations.";\r
+                        result.add(message);\r
+                    } else{\r
+                        message = "The Taxon can't be deleted as long as it belongs to a taxon node.";\r
+                        result.add(message);\r
+                    }\r
+                }\r
+                if (ref instanceof PolytomousKeyNode){\r
+                    message = "The Taxon can't be deleted as long as it is referenced by a polytomous key node.";\r
+                    result.add(message);\r
+                }\r
+\r
+                if (HibernateProxyHelper.isInstanceOf(ref, IIdentificationKey.class)){\r
                    message = "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";\r
                    result.add(message);\r
                    message = "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";\r
                    result.add(message);\r
-                   \r
+\r
                 }\r
 \r
 \r
                 }\r
 \r
 \r
@@ -3144,13 +3159,142 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
             }\r
 \r
 \r
             }\r
 \r
-       }\r
-       \r
-       return result;\r
+        }\r
+\r
+        return result;\r
     }\r
 \r
     }\r
 \r
+    @Override\r
+    public IncludedTaxaDTO listIncludedTaxa(UUID taxonUuid, IncludedTaxonConfiguration config) {\r
+        IncludedTaxaDTO result = new IncludedTaxaDTO(taxonUuid);\r
 \r
 \r
+        //preliminary implementation\r
 \r
 \r
+        Set<Taxon> taxa = new HashSet<Taxon>();\r
+        TaxonBase taxonBase = find(taxonUuid);\r
+        if (taxonBase == null){\r
+            return new IncludedTaxaDTO();\r
+        }else if (taxonBase.isInstanceOf(Taxon.class)){\r
+            Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);\r
+            taxa.add(taxon);\r
+        }else if (taxonBase.isInstanceOf(Synonym.class)){\r
+            //TODO partial synonyms ??\r
+            //TODO synonyms in general\r
+            Synonym syn = CdmBase.deproxy(taxonBase, Synonym.class);\r
+            taxa.addAll(syn.getAcceptedTaxa());\r
+        }else{\r
+            throw new IllegalArgumentException("Unhandled class " + taxonBase.getClass().getSimpleName());\r
+        }\r
 \r
 \r
+        Set<Taxon> related = makeRelatedIncluded(taxa, result, config);\r
+        int i = 0;\r
+        while((! related.isEmpty()) && i++ < 100){  //to avoid\r
+             related = makeRelatedIncluded(related, result, config);\r
+        }\r
 \r
 \r
+        return result;\r
     }\r
     }\r
+\r
+    /**\r
+     * Computes all children and conceptually congruent and included taxa and adds them to the existingTaxa\r
+     * data structure.\r
+     * @return the set of conceptually related taxa for further use\r
+     */\r
+    /**\r
+     * @param uncheckedTaxa\r
+     * @param existingTaxa\r
+     * @param config\r
+     * @return\r
+     */\r
+    private Set<Taxon> makeRelatedIncluded(Set<Taxon> uncheckedTaxa, IncludedTaxaDTO existingTaxa, IncludedTaxonConfiguration config) {\r
+\r
+        //children\r
+        Set<TaxonNode> taxonNodes = new HashSet<TaxonNode>();\r
+        for (Taxon taxon: uncheckedTaxa){\r
+            taxonNodes.addAll(taxon.getTaxonNodes());\r
+        }\r
+\r
+        Set<Taxon> children = new HashSet<Taxon>();\r
+        if (! config.onlyCongruent){\r
+            for (TaxonNode node: taxonNodes){\r
+                List<TaxonNode> childNodes = nodeService.loadChildNodesOfTaxonNode(node, null, true, false);\r
+                for (TaxonNode child : childNodes){\r
+                    children.add(child.getTaxon());\r
+                }\r
+            }\r
+            children.remove(null);  // just to be on the save side\r
+        }\r
+\r
+        Iterator<Taxon> it = children.iterator();\r
+        while(it.hasNext()){\r
+            UUID uuid = it.next().getUuid();\r
+            if (existingTaxa.contains(uuid)){\r
+                it.remove();\r
+            }else{\r
+                existingTaxa.addIncludedTaxon(uuid, new ArrayList<UUID>(), false);\r
+            }\r
+        }\r
+\r
+        //concept relations\r
+        Set<Taxon> uncheckedAndChildren = new HashSet<Taxon>(uncheckedTaxa);\r
+        uncheckedAndChildren.addAll(children);\r
+\r
+        Set<Taxon> relatedTaxa = makeConceptIncludedTaxa(uncheckedAndChildren, existingTaxa, config);\r
+\r
+\r
+        Set<Taxon> result = new HashSet<Taxon>(relatedTaxa);\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * Computes all conceptually congruent or included taxa and adds them to the existingTaxa data structure.\r
+     * @return the set of these computed taxa\r
+     */\r
+    private Set<Taxon> makeConceptIncludedTaxa(Set<Taxon> unchecked, IncludedTaxaDTO existingTaxa, IncludedTaxonConfiguration config) {\r
+        Set<Taxon> result = new HashSet<Taxon>();\r
+\r
+        for (Taxon taxon : unchecked){\r
+            Set<TaxonRelationship> fromRelations = taxon.getRelationsFromThisTaxon();\r
+            Set<TaxonRelationship> toRelations = taxon.getRelationsToThisTaxon();\r
+\r
+            for (TaxonRelationship fromRel : fromRelations){\r
+                if (config.includeDoubtful == false && fromRel.isDoubtful()){\r
+                    continue;\r
+                }\r
+                if (fromRel.getType().equals(TaxonRelationshipType.CONGRUENT_TO()) ||\r
+                        !config.onlyCongruent && fromRel.getType().equals(TaxonRelationshipType.INCLUDES()) ||\r
+                        !config.onlyCongruent && fromRel.getType().equals(TaxonRelationshipType.CONGRUENT_OR_INCLUDES())\r
+                        ){\r
+                    result.add(fromRel.getToTaxon());\r
+                }\r
+            }\r
+\r
+            for (TaxonRelationship toRel : toRelations){\r
+                if (config.includeDoubtful == false && toRel.isDoubtful()){\r
+                    continue;\r
+                }\r
+                if (toRel.getType().equals(TaxonRelationshipType.CONGRUENT_TO())){\r
+                    result.add(toRel.getFromTaxon());\r
+                }\r
+            }\r
+        }\r
+\r
+        Iterator<Taxon> it = result.iterator();\r
+        while(it.hasNext()){\r
+            UUID uuid = it.next().getUuid();\r
+            if (existingTaxa.contains(uuid)){\r
+                it.remove();\r
+            }else{\r
+                existingTaxa.addIncludedTaxon(uuid, new ArrayList<UUID>(), false);\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+    @Override\r
+    public List<TaxonBase> findTaxaByName(MatchingTaxonConfigurator config){\r
+        List<TaxonBase> taxonList = dao.getTaxaByName(true, false, false, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, 0, config.getPropertyPath());\r
+        return taxonList;\r
+    }\r
+\r
+\r
+}\r