merge validation2 and model 3.5 into trunk
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonServiceImpl.java
index cf7701c4866cd9bc194478e79ea4809feae771fe..7c21fc2d77868fb2fe4926982b7be8c55c70943b 100644 (file)
@@ -21,6 +21,8 @@ import java.util.Map;
 import java.util.Set;\r
 import java.util.UUID;\r
 \r
+import javax.persistence.EntityNotFoundException;\r
+\r
 import org.apache.log4j.Logger;\r
 import org.apache.lucene.index.CorruptIndexException;\r
 import org.apache.lucene.queryParser.ParseException;\r
@@ -35,11 +37,15 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;\r
 import org.springframework.transaction.annotation.Transactional;\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.dto.FindByIdentifierDTO;\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
@@ -62,6 +68,7 @@ import eu.etaxonomy.cdm.hibernate.search.GroupByTaxonClassBridge;
 import eu.etaxonomy.cdm.hibernate.search.MultilanguageTextFieldBridge;\r
 import eu.etaxonomy.cdm.model.CdmBaseType;\r
 import eu.etaxonomy.cdm.model.common.CdmBase;\r
+import eu.etaxonomy.cdm.model.common.DefinedTerm;\r
 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;\r
 import eu.etaxonomy.cdm.model.common.IdentifiableSource;\r
 import eu.etaxonomy.cdm.model.common.Language;\r
@@ -77,7 +84,7 @@ import eu.etaxonomy.cdm.model.description.Distribution;
 import eu.etaxonomy.cdm.model.description.Feature;\r
 import eu.etaxonomy.cdm.model.description.IIdentificationKey;\r
 import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;\r
-import eu.etaxonomy.cdm.model.description.PresenceAbsenceTermBase;\r
+import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;\r
 import eu.etaxonomy.cdm.model.description.SpecimenDescription;\r
 import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
 import eu.etaxonomy.cdm.model.description.TaxonInteraction;\r
@@ -86,18 +93,21 @@ import eu.etaxonomy.cdm.model.location.NamedArea;
 import eu.etaxonomy.cdm.model.media.Media;\r
 import eu.etaxonomy.cdm.model.media.MediaRepresentation;\r
 import eu.etaxonomy.cdm.model.media.MediaUtils;\r
-import eu.etaxonomy.cdm.model.molecular.Amplification;\r
+import eu.etaxonomy.cdm.model.molecular.AmplificationResult;\r
 import eu.etaxonomy.cdm.model.molecular.DnaSample;\r
 import eu.etaxonomy.cdm.model.molecular.Sequence;\r
 import eu.etaxonomy.cdm.model.molecular.SingleRead;\r
 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;\r
+import eu.etaxonomy.cdm.model.name.NameRelationship;\r
 import eu.etaxonomy.cdm.model.name.Rank;\r
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
 import eu.etaxonomy.cdm.model.name.ZoologicalName;\r
 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;\r
+import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;\r
 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;\r
 import eu.etaxonomy.cdm.model.reference.Reference;\r
 import eu.etaxonomy.cdm.model.taxon.Classification;\r
+import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;\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
@@ -111,6 +121,7 @@ import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao;
 import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;\r
 import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;\r
 import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;\r
+import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;\r
 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;\r
 import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;\r
 import eu.etaxonomy.cdm.persistence.query.MatchMode;\r
@@ -145,7 +156,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     @Autowired\r
     private ITaxonNodeService nodeService;\r
 \r
-\r
     @Autowired\r
     private ICdmGenericDao genericDao;\r
 \r
@@ -158,6 +168,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     @Autowired\r
     private IOccurrenceDao occurrenceDao;\r
 \r
+    @Autowired\r
+    private IClassificationDao classificationDao;\r
+\r
     @Autowired\r
     private AbstractBeanInitializer beanInitializer;\r
 \r
@@ -180,28 +193,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         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
@@ -216,18 +207,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         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
-    /* (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
@@ -294,10 +278,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         SynonymRelationshipType relTypeForGroup = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();\r
         List<Synonym> heteroSynonyms = acceptedTaxon.getSynonymsInGroup(synonymHomotypicGroup);\r
+        Set<NameRelationship> basionymsAndReplacedSynonyms = synonymHomotypicGroup.getBasionymAndReplacedSynonymRelations();\r
 \r
         for (Synonym heteroSynonym : heteroSynonyms){\r
             if (synonym.equals(heteroSynonym)){\r
                 acceptedTaxon.removeSynonym(heteroSynonym, false);\r
+\r
             }else{\r
                 //move synonyms in same homotypic group to new accepted taxon\r
                 heteroSynonym.replaceAcceptedTaxon(newAcceptedTaxon, relTypeForGroup, copyCitationInfo, citation, microCitation);\r
@@ -310,7 +296,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 //                     deleteSynonym(synonym, taxon, false);\r
             try {\r
                 this.dao.flush();\r
-                this.deleteSynonym(synonym, acceptedTaxon, new SynonymDeletionConfigurator());\r
+                SynonymDeletionConfigurator config = new SynonymDeletionConfigurator();\r
+                config.setDeleteNameIfPossible(false);\r
+                this.deleteSynonym(synonym, acceptedTaxon, config);\r
 \r
             } catch (Exception e) {\r
                 logger.info("Can't delete old synonym from database");\r
@@ -327,9 +315,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         // Get name from synonym\r
         TaxonNameBase<?, ?> synonymName = synonym.getName();\r
 \r
-        // remove synonym from taxon\r
+      /*  // remove synonym from taxon\r
         toTaxon.removeSynonym(synonym);\r
-\r
+*/\r
         // Create a taxon with synonym name\r
         Taxon fromTaxon = Taxon.NewInstance(synonymName, null);\r
 \r
@@ -338,7 +326,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         // since we are swapping names, we have to detach the name from the synonym completely.\r
         // Otherwise the synonym will still be in the list of typified names.\r
-        synonym.getName().removeTaxonBase(synonym);\r
+       // synonym.getName().removeTaxonBase(synonym);\r
+        this.deleteSynonym(synonym, null);\r
 \r
         return fromTaxon;\r
     }\r
@@ -357,7 +346,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
 \r
         // Switch groups\r
-        oldHomotypicalGroup.removeTypifiedName(synonymName);\r
+        oldHomotypicalGroup.removeTypifiedName(synonymName, false);\r
         newHomotypicalGroup.addTypifiedName(synonymName);\r
 \r
         //remove existing basionym relationships\r
@@ -426,9 +415,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         this.dao = dao;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @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, 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
@@ -441,9 +427,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return new DefaultPagerImpl<TaxonBase>(pageNumber, numberOfResults, pageSize, results);\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
     @Override\r
     public List<TaxonBase> listTaxaByName(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
@@ -456,9 +439,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return results;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-     */\r
     @Override\r
     public List<TaxonRelationship> listToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){\r
         Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);\r
@@ -470,9 +450,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return results;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-     */\r
     @Override\r
     public Pager<TaxonRelationship> pageToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
         Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);\r
@@ -484,9 +461,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-     */\r
     @Override\r
     public List<TaxonRelationship> listFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){\r
         Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);\r
@@ -498,9 +472,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return results;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-     */\r
     @Override\r
     public Pager<TaxonRelationship> pageFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
         Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);\r
@@ -512,15 +483,50 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);\r
     }\r
 \r
-    /**\r
-     * @param taxon\r
-     * @param includeRelationships\r
-     * @param maxDepth\r
-     * @param limit\r
-     * @param starts\r
-     * @param propertyPaths\r
-     * @return an List which is not specifically ordered\r
-     */\r
+    @Override\r
+    public List<Taxon> listAcceptedTaxaFor(UUID synonymUuid, UUID classificationUuid, Integer pageSize, Integer pageNumber,\r
+            List<OrderHint> orderHints, List<String> propertyPaths){\r
+        return pageAcceptedTaxaFor(synonymUuid, classificationUuid, pageSize, pageNumber, orderHints, propertyPaths).getRecords();\r
+    }\r
+\r
+    @Override\r
+    public Pager<Taxon> pageAcceptedTaxaFor(UUID synonymUuid, UUID classificationUuid, Integer pageSize, Integer pageNumber,\r
+            List<OrderHint> orderHints, List<String> propertyPaths){\r
+\r
+        List<Taxon> list = new ArrayList<Taxon>();\r
+        Long count = 0l;\r
+\r
+        Synonym synonym = null;\r
+\r
+        try {\r
+            synonym = (Synonym) dao.load(synonymUuid);\r
+        } catch (ClassCastException e){\r
+            throw new EntityNotFoundException("The TaxonBase entity referenced by " + synonymUuid + " is not a Synonmy");\r
+        } catch (NullPointerException e){\r
+            throw new EntityNotFoundException("No TaxonBase entity found for " + synonymUuid);\r
+        }\r
+\r
+        Classification classificationFilter = null;\r
+        if(classificationUuid != null){\r
+            try {\r
+            classificationFilter = classificationDao.load(classificationUuid);\r
+            } catch (NullPointerException e){\r
+                throw new EntityNotFoundException("No Classification entity found for " + classificationUuid);\r
+            }\r
+            if(classificationFilter == null){\r
+\r
+            }\r
+        }\r
+\r
+        count = dao.countAcceptedTaxaFor(synonym, classificationFilter) ;\r
+        if(count > (pageSize * pageNumber)){\r
+            list = dao.listAcceptedTaxaFor(synonym, classificationFilter, pageSize, pageNumber, orderHints, propertyPaths);\r
+        }\r
+\r
+        return new DefaultPagerImpl<Taxon>(pageNumber, count.intValue(), pageSize, list);\r
+    }\r
+\r
+\r
     @Override\r
     public Set<Taxon> listRelatedTaxa(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships, Integer maxDepth,\r
             Integer limit, Integer start, List<String> propertyPaths) {\r
@@ -548,6 +554,10 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             taxa.add(taxon);\r
         }\r
 \r
+        if(includeRelationships.isEmpty()){\r
+            return taxa;\r
+        }\r
+\r
         if(maxDepth != null) {\r
             maxDepth--;\r
         }\r
@@ -618,6 +628,27 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return new DefaultPagerImpl<SynonymRelationship>(pageNumber, numberOfResults, pageSize, results);\r
     }\r
 \r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)\r
+     */\r
+    @Override\r
+    public List<List<Synonym>> getSynonymsByHomotypicGroup(Taxon taxon, List<String> propertyPaths){\r
+         List<List<Synonym>> result = new ArrayList<List<Synonym>>();\r
+        Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);\r
+\r
+        //homotypic\r
+        result.add(t.getHomotypicSynonymsByHomotypicGroup());\r
+\r
+        //heterotypic\r
+        List<HomotypicalGroup> homotypicalGroups = t.getHeterotypicSynonymyGroups();\r
+        for(HomotypicalGroup homotypicalGroup : homotypicalGroups){\r
+            result.add(t.getSynonymsInGroup(homotypicalGroup));\r
+        }\r
+\r
+        return result;\r
+\r
+    }\r
+\r
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)\r
      */\r
@@ -642,25 +673,23 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     }\r
 \r
     @Override\r
-    public List<UuidAndTitleCache<TaxonBase>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator){\r
-\r
-        List<UuidAndTitleCache<TaxonBase>> result = new ArrayList<UuidAndTitleCache<TaxonBase>>();\r
-//        Class<? extends TaxonBase> clazz = null;\r
-//        if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {\r
-//            clazz = TaxonBase.class;\r
-//            //propertyPath.addAll(configurator.getTaxonPropertyPath());\r
-//            //propertyPath.addAll(configurator.getSynonymPropertyPath());\r
-//        } else if(configurator.isDoTaxa()) {\r
-//            clazz = Taxon.class;\r
-//            //propertyPath = configurator.getTaxonPropertyPath();\r
-//        } else if (configurator.isDoSynonyms()) {\r
-//            clazz = Synonym.class;\r
-//            //propertyPath = configurator.getSynonymPropertyPath();\r
-//        }\r
+    public List<UuidAndTitleCache<IdentifiableEntity>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator){\r
 \r
+        List<UuidAndTitleCache<IdentifiableEntity>> results = new ArrayList<UuidAndTitleCache<IdentifiableEntity>>();\r
 \r
-        result = dao.getTaxaByNameForEditor(configurator.isDoTaxa(), configurator.isDoSynonyms(), configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());\r
-        return result;\r
+\r
+        if (configurator.isDoSynonyms() || configurator.isDoTaxa() || configurator.isDoNamesWithoutTaxa()){\r
+               results = dao.getTaxaByNameForEditor(configurator.isDoTaxa(), configurator.isDoSynonyms(), configurator.isDoNamesWithoutTaxa(), configurator.isDoMisappliedNames(),configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());\r
+        }\r
+        if (configurator.isDoTaxaByCommonNames()) {\r
+            //if(configurator.getPageSize() == null ){\r
+                List<UuidAndTitleCache<IdentifiableEntity>> commonNameResults = dao.getTaxaByCommonNameForEditor(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());\r
+                if(commonNameResults != null){\r
+                    results.addAll(commonNameResults);\r
+                }\r
+           // }\r
+        }\r
+        return results;\r
     }\r
 \r
     /* (non-Javadoc)\r
@@ -736,10 +765,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
-                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
@@ -795,21 +822,26 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             Boolean limitToGalleries, Boolean includeTaxonDescriptions, Boolean includeOccurrences,\r
             Boolean includeTaxonNameDescriptions, List<String> propertyPath) {\r
 \r
+        logger.trace("listMedia() - START");\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
 \r
         // --- resolve related taxa\r
-        if (includeRelationships != null) {\r
+        if (includeRelationships != null && ! includeRelationships.isEmpty()) {\r
+            logger.trace("listMedia() - resolve related taxa");\r
             taxa = listRelatedTaxa(taxon, includeRelationships, null, null, null, null);\r
         }\r
 \r
         taxa.add((Taxon) dao.load(taxon.getUuid()));\r
 \r
         if(includeTaxonDescriptions != null && includeTaxonDescriptions){\r
+            logger.trace("listMedia() - includeTaxonDescriptions");\r
             List<TaxonDescription> taxonDescriptions = new ArrayList<TaxonDescription>();\r
             // --- TaxonDescriptions\r
             for (Taxon t : taxa) {\r
@@ -819,14 +851,23 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 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
+            //put images from image gallery first (#3242)\r
+            taxonMedia.addAll(nonImageGalleryImages);\r
         }\r
 \r
+\r
         if(includeOccurrences != null && includeOccurrences) {\r
+            logger.trace("listMedia() - includeOccurrences");\r
             Set<SpecimenOrObservationBase> specimensOrObservations = new HashSet<SpecimenOrObservationBase>();\r
             // --- Specimens\r
             for (Taxon t : taxa) {\r
@@ -867,7 +908,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                     for (Sequence sequence : sequences) {\r
                         Set<Media> dnaRelatedMedia = new HashSet<Media>();\r
                         for (SingleRead singleRead : sequence.getSingleReads()){\r
-                            Amplification amplification = singleRead.getAmplification();\r
+                            AmplificationResult amplification = singleRead.getAmplificationResult();\r
                             dnaRelatedMedia.add(amplification.getGelPhoto());\r
                             dnaRelatedMedia.add(singleRead.getPherogram());\r
                             dnaRelatedMedia.remove(null);\r
@@ -880,6 +921,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         }\r
 \r
         if(includeTaxonNameDescriptions != null && includeTaxonNameDescriptions) {\r
+            logger.trace("listMedia() - includeTaxonNameDescriptions");\r
             // --- TaxonNameDescription\r
             Set<TaxonNameDescription> nameDescriptions = new HashSet<TaxonNameDescription>();\r
             for (Taxon t : taxa) {\r
@@ -897,7 +939,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             }\r
         }\r
 \r
+\r
+        logger.trace("listMedia() - initialize");\r
         beanInitializer.initializeAll(taxonMedia, propertyPath);\r
+\r
+        logger.trace("listMedia() - END");\r
+\r
         return taxonMedia;\r
     }\r
 \r
@@ -941,11 +988,15 @@ 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 UUID deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config, Classification classification) throws DataChangeNoRollbackException {\r
-        if (config == null){\r
+    public DeleteResult deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config, Classification classification)  {\r
+\r
+       if (config == null){\r
             config = new TaxonDeletionConfigurator();\r
         }\r
 \r
+        DeleteResult result = isDeletable(taxon, config);\r
+\r
+        if (result.isOk()){\r
             // --- DeleteSynonymRelations\r
             if (config.isDeleteSynonymRelations()){\r
                 boolean removeSynonymNameFromHomotypicalGroup = false;\r
@@ -980,7 +1031,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 if (taxon.getTaxonRelations().size() > 0){\r
                     String message = "Taxon can't be deleted as it is related to another taxon. " +\r
                             "Remove taxon from all relations to other taxa prior to deletion.";\r
-                    throw new ReferencedObjectUndeletableException(message);\r
+                   // throw new ReferencedObjectUndeletableException(message);\r
                 }\r
             } else{\r
                 for (TaxonRelationship taxRel: taxon.getTaxonRelations()){\r
@@ -1012,32 +1063,36 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             //         TaxonDescription\r
             if (config.isDeleteDescriptions()){\r
                 Set<TaxonDescription> descriptions = taxon.getDescriptions();\r
-\r
+                List<TaxonDescription> removeDescriptions = new ArrayList<TaxonDescription>();\r
                 for (TaxonDescription desc: descriptions){\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
+                        //throw new ReferencedObjectUndeletableException(message);\r
                     }\r
+                    removeDescriptions.add(desc);\r
                     descriptionService.delete(desc);\r
+\r
+                }\r
+                for (TaxonDescription desc: removeDescriptions){\r
                     taxon.removeDescription(desc);\r
                 }\r
             }\r
 \r
 \r
-            //check references with only reverse mapping\r
+         /*   //check references with only reverse mapping\r
         String message = checkForReferences(taxon);\r
         if (message != null){\r
-            throw new ReferencedObjectUndeletableException(message.toString());\r
-        }\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
+                //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
@@ -1062,16 +1117,18 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                             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
-                        List<TaxonNode> nodesList = new ArrayList<TaxonNode>();\r
+                        Set<ITaxonTreeNode> nodesList = new HashSet<ITaxonTreeNode>();\r
                         nodesList.addAll(taxon.getTaxonNodes());\r
 \r
-                            for (TaxonNode taxonNode: nodesList){\r
-                                if(deleteChildren){\r
-                                    Object[] childNodes = taxonNode.getChildNodes().toArray();\r
+                            for (ITaxonTreeNode treeNode: nodesList){\r
+                                TaxonNode taxonNode = (TaxonNode) treeNode;\r
+                                if(!deleteChildren){\r
+                                   /* Object[] childNodes = taxonNode.getChildNodes().toArray();\r
+                                    //nodesList.addAll(taxonNode.getChildNodes());\r
                                     for (Object childNode: childNodes){\r
                                         TaxonNode childNodeCast = (TaxonNode) childNode;\r
                                         deleteTaxon(childNodeCast.getTaxon(), config, classification);\r
@@ -1081,9 +1138,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                                     /*for (TaxonNode childNode: taxonNode.getChildNodes()){\r
                                         deleteTaxon(childNode.getTaxon(), config, classification);\r
 \r
-                                    }*/\r
-                                    //taxon.removeTaxonNode(taxonNode);\r
+                                    }\r
+                                   // taxon.removeTaxonNode(taxonNode);\r
+                                    //nodeService.delete(taxonNode);\r
                                 } else{\r
+                                    */\r
                                     Object[] childNodes = taxonNode.getChildNodes().toArray();\r
                                     for (Object childNode: childNodes){\r
                                         TaxonNode childNodeCast = (TaxonNode) childNode;\r
@@ -1093,33 +1152,52 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                                     //taxon.removeTaxonNode(taxonNode);\r
                                 }\r
                             }\r
-\r
-                        nodeService.deleteTaxonNodes(nodesList);\r
+                        config.getTaxonNodeConfig().setDeleteTaxon(false);\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
-                         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
+             //PolytomousKey TODO\r
+\r
+\r
             //TaxonNameBase\r
             if (config.isDeleteNameIfPossible()){\r
-                try {\r
+\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
+                    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
-                        nameService.delete(name, config.getNameDeletionConfig());\r
+                        //name.removeTaxonBase(taxon);\r
+                        //nameService.saveOrUpdate(name);\r
+                        taxon.setName(null);\r
+                        //dao.delete(taxon);\r
+                        DeleteResult nameResult = new DeleteResult();\r
+\r
+                        //remove name if possible (and required)\r
+                        if (name != null && config.isDeleteNameIfPossible()){\r
+                               nameResult = nameService.delete(name, config.getNameDeletionConfig());\r
+                        }\r
+                        \r
+                        if (nameResult.isError()){\r
+                               //result.setError();\r
+                               result.addRelatedObject(name);\r
+                               result.addExceptions(nameResult.getExceptions());\r
+                        }\r
+\r
                     }\r
-                } catch (ReferencedObjectUndeletableException e) {\r
-                    //do nothing\r
-                    if (logger.isDebugEnabled()){logger.debug("Name could not be deleted");}\r
 \r
-                }\r
             }\r
 \r
 //             TaxonDescription\r
@@ -1140,17 +1218,32 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                     }\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
-                if (!config.isDeleteInAllClassifications() && classification != null) {\r
-                    message += "The Taxonnode in " + classification.getTitleCache() + " was deleted.";\r
-                }\r
-                throw new ReferencedObjectUndeletableException(message);\r
-            }\r
+            if ((taxon.getTaxonNodes() == null || taxon.getTaxonNodes().size()== 0)  ){\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
+               result.setError();\r
+               result.addException(new Exception("The Taxon can't be deleted."));\r
 \r
+            }\r
+        }\r
+//        }else {\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
+        return result;\r
 \r
     }\r
 \r
@@ -1165,22 +1258,39 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             }\r
 \r
 \r
-            //PolytomousKeyNode\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
 \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
+          //TaxonInteraction\r
+            if (referencingObject.isInstanceOf(DeterminationEvent.class)){\r
+                String message = "Taxon can't be deleted as it is used in a determination event";\r
+                return message;\r
+            }\r
+\r
         }\r
+\r
         referencingObjects = null;\r
         return null;\r
     }\r
 \r
+    private boolean checkForPolytomousKeys(Taxon taxon){\r
+        boolean result = false;\r
+        List<CdmBase> list = genericDao.getCdmBasesByFieldAndClass(PolytomousKeyNode.class, "taxon", taxon);\r
+        if (!list.isEmpty()) {\r
+            result = true;\r
+        }\r
+        return result;\r
+    }\r
+\r
     @Transactional(readOnly = false)\r
     public UUID delete(Synonym syn){\r
         UUID result = syn.getUuid();\r
@@ -1188,13 +1298,15 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         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
-    public void deleteSynonym(Synonym synonym, SynonymDeletionConfigurator config) {\r
-        deleteSynonym(synonym, null, config);\r
+    public DeleteResult deleteSynonym(Synonym synonym, SynonymDeletionConfigurator config) {\r
+        return deleteSynonym(synonym, null, config);\r
 \r
     }\r
 \r
@@ -1204,50 +1316,76 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      */\r
     @Transactional(readOnly = false)\r
     @Override\r
-    public void deleteSynonym(Synonym synonym, Taxon taxon, SynonymDeletionConfigurator config) {\r
-        if (synonym == null){\r
-            return;\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
         if (config == null){\r
             config = new SynonymDeletionConfigurator();\r
         }\r
-        synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);\r
+        result = isDeletable(synonym, config);\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
+        if (result.isOk()){\r
+            synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);\r
 \r
-        //remove synonym (if necessary)\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
+               relatedTaxon = HibernateProxyHelper.deproxy(relatedTaxon, Taxon.class);\r
+                relatedTaxon.removeSynonym(synonym, false);\r
+                this.saveOrUpdate(relatedTaxon);\r
+            }\r
+            this.saveOrUpdate(synonym);\r
 \r
+            //TODO remove name from homotypical group?\r
 \r
-        if (synonym.getSynonymRelations().isEmpty()){\r
-            TaxonNameBase<?,?> name = synonym.getName();\r
-            synonym.setName(null);\r
-            dao.delete(synonym);\r
+            //remove synonym (if necessary)\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 && config.isDeleteNameIfPossible()){\r
+\r
+                        DeleteResult nameDeleteresult = nameService.delete(name, config.getNameDeletionConfig());\r
+                        if (nameDeleteresult.isAbort()){\r
+                               result.addExceptions(nameDeleteresult.getExceptions());\r
+                               result.addUpdatedObject(name);\r
+                        }\r
 \r
-            //remove name if possible (and required)\r
-            if (name != null && config.isDeleteNameIfPossible()){\r
-                try{\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
                 }\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
+\r
         }\r
+        return result;\r
+//        else{\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
@@ -1496,6 +1634,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                     if (newRefDetail == null && keepReference){\r
                         newRefDetail = synRelation.getCitationMicroReference();\r
                     }\r
+                    newTaxon = HibernateProxyHelper.deproxy(newTaxon, Taxon.class);\r
+                    fromTaxon = HibernateProxyHelper.deproxy(fromTaxon, Taxon.class);\r
                     SynonymRelationship newSynRelation = newTaxon.addSynonym(syn, newSynonymRelationshipType, newReference, newRefDetail);\r
                     fromTaxon.removeSynonymRelation(synRelation, false);\r
 //\r
@@ -1511,6 +1651,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             }\r
 \r
         }\r
+        saveOrUpdate(fromTaxon);\r
         saveOrUpdate(newTaxon);\r
         //Assert that there is a result\r
         if (result == null){\r
@@ -1546,7 +1687,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {\r
 \r
 \r
-        LuceneSearch luceneSearch = prepareFindByFullTextSearch(clazz, queryString, classification, languages, highlightFragments);\r
+        LuceneSearch luceneSearch = prepareFindByFullTextSearch(clazz, queryString, classification, languages, highlightFragments, null);\r
 \r
         // --- execute search\r
         TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);\r
@@ -1564,7 +1705,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     }\r
 \r
     @Override\r
-    public Pager<SearchResult<TaxonBase>> findByDistribution(List<NamedArea> areaFilter, List<PresenceAbsenceTermBase<?>> statusFilter,\r
+    public Pager<SearchResult<TaxonBase>> findByDistribution(List<NamedArea> areaFilter, List<PresenceAbsenceTerm> statusFilter,\r
             Classification classification,\r
             Integer pageSize, Integer pageNumber,\r
             List<OrderHint> orderHints, List<String> propertyPaths) throws IOException, ParseException {\r
@@ -1592,18 +1733,21 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * @param classification\r
      * @param languages\r
      * @param highlightFragments\r
+     * @param sortFields TODO\r
      * @param directorySelectClass\r
      * @return\r
      */\r
     protected LuceneSearch prepareFindByFullTextSearch(Class<? extends CdmBase> clazz, String queryString, Classification classification, List<Language> languages,\r
-            boolean highlightFragments) {\r
+            boolean highlightFragments, SortField[] sortFields) {\r
         BooleanQuery finalQuery = new BooleanQuery();\r
         BooleanQuery textQuery = new BooleanQuery();\r
 \r
         LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, TaxonBase.class);\r
         QueryFactory taxonBaseQueryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonBase.class);\r
 \r
-        SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};\r
+        if(sortFields == null){\r
+            sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};\r
+        }\r
         luceneSearch.setSortFields(sortFields);\r
 \r
         // ---- search criteria\r
@@ -1636,16 +1780,17 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * <li>direct, everted: {@link Direction.relatedTo}: TaxonRelationShip.relatedTo.id --&gt; Taxon.id </li>\r
      * <li>inverse: {@link Direction.relatedFrom}:  TaxonRelationShip.relatedFrom.id --&gt; Taxon.id </li>\r
      * <ul>\r
-     *\r
      * @param queryString\r
      * @param classification\r
      * @param languages\r
      * @param highlightFragments\r
+     * @param sortFields TODO\r
+     *\r
      * @return\r
      * @throws IOException\r
      */\r
     protected LuceneSearch prepareFindByTaxonRelationFullTextSearch(TaxonRelationshipEdge edge, String queryString, Classification classification, List<Language> languages,\r
-            boolean highlightFragments) throws IOException {\r
+            boolean highlightFragments, SortField[] sortFields) throws IOException {\r
 \r
         String fromField;\r
         String queryTermField;\r
@@ -1674,7 +1819,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         joinFromQuery.add(taxonBaseQueryFactory.newEntityIdQuery("type.id", edge.getTaxonRelationshipType()), Occur.MUST);\r
         Query joinQuery = taxonBaseQueryFactory.newJoinQuery(fromField, toField, joinFromQuery, TaxonRelationship.class);\r
 \r
-        SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};\r
+        if(sortFields == null){\r
+            sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};\r
+        }\r
         luceneSearch.setSortFields(sortFields);\r
 \r
         finalQuery.add(joinQuery, Occur.MUST);\r
@@ -1699,7 +1846,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     @Override\r
     public Pager<SearchResult<TaxonBase>> findTaxaAndNamesByFullText(\r
             EnumSet<TaxaAndNamesSearchMode> searchModes, String queryString, Classification classification,\r
-            Set<NamedArea> namedAreas, Set<PresenceAbsenceTermBase<?>> distributionStatus, List<Language> languages,\r
+            Set<NamedArea> namedAreas, Set<PresenceAbsenceTerm> distributionStatus, List<Language> languages,\r
             boolean highlightFragments, Integer pageSize,\r
             Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths)\r
             throws CorruptIndexException, IOException, ParseException, LuceneMultiSearchException {\r
@@ -1715,13 +1862,13 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         // convert sets to lists\r
         List<NamedArea> namedAreaList = null;\r
-        List<PresenceAbsenceTermBase<?>>distributionStatusList = null;\r
+        List<PresenceAbsenceTerm>distributionStatusList = null;\r
         if(namedAreas != null){\r
             namedAreaList = new ArrayList<NamedArea>(namedAreas.size());\r
             namedAreaList.addAll(namedAreas);\r
         }\r
         if(distributionStatus != null){\r
-            distributionStatusList = new ArrayList<PresenceAbsenceTermBase<?>>(distributionStatus.size());\r
+            distributionStatusList = new ArrayList<PresenceAbsenceTerm>(distributionStatus.size());\r
             distributionStatusList.addAll(distributionStatus);\r
         }\r
 \r
@@ -1730,6 +1877,20 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             searchModes = EnumSet.of(TaxaAndNamesSearchMode.doTaxa);\r
         }\r
 \r
+        // set sort order and thus override any sort orders which may have been\r
+        // defindes by prepare*Search methods\r
+        if(orderHints == null){\r
+            orderHints = OrderHint.NOMENCLATURAL_SORT_ORDER;\r
+        }\r
+        SortField[] sortFields = new SortField[orderHints.size()];\r
+        int i = 0;\r
+        for(OrderHint oh : orderHints){\r
+            sortFields[i++] = oh.toSortField();\r
+        }\r
+//        SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("id", SortField.STRING, false)};\r
+//        SortField[] sortFields = new SortField[]{new SortField(NomenclaturalSortOrderBrigde.NAME_SORT_FIELD_NAME, SortField.STRING, false)};\r
+\r
+\r
         boolean addDistributionFilter = namedAreas != null && namedAreas.size() > 0;\r
 \r
         List<LuceneSearch> luceneSearches = new ArrayList<LuceneSearch>();\r
@@ -1787,7 +1948,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             } else if (!searchModes.contains(TaxaAndNamesSearchMode.doTaxa) && searchModes.contains(TaxaAndNamesSearchMode.doSynonyms)) {\r
                 taxonBaseSubclass = Synonym.class;\r
             }\r
-            luceneSearches.add(prepareFindByFullTextSearch(taxonBaseSubclass, queryString, classification, languages, highlightFragments));\r
+            luceneSearches.add(prepareFindByFullTextSearch(taxonBaseSubclass, queryString, classification, languages, highlightFragments, sortFields));\r
             idFieldMap.put(CdmBaseType.TAXON, "id");\r
             /* A) does not work!!!!\r
             if(addDistributionFilter){\r
@@ -1831,6 +1992,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             LuceneSearch byCommonNameSearch = new LuceneSearch(luceneIndexToolProvider, GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, Taxon.class);\r
             byCommonNameSearch.setCdmTypRestriction(Taxon.class);\r
             byCommonNameSearch.setQuery(byCommonNameJoinQuery);\r
+            byCommonNameSearch.setSortFields(sortFields);\r
             idFieldMap.put(CdmBaseType.TAXON, "id");\r
 \r
             luceneSearches.add(byCommonNameSearch);\r
@@ -1863,7 +2025,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             //\r
             luceneSearches.add(prepareFindByTaxonRelationFullTextSearch(\r
                     new TaxonRelationshipEdge(TaxonRelationshipType.MISAPPLIED_NAME_FOR(), Direction.relatedTo),\r
-                    queryString, classification, languages, highlightFragments));\r
+                    queryString, classification, languages, highlightFragments, sortFields));\r
             idFieldMap.put(CdmBaseType.TAXON, "id");\r
 \r
             if(addDistributionFilter){\r
@@ -1931,6 +2093,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         if (addDistributionFilter){\r
             multiSearch.setFilter(multiIndexByAreaFilter);\r
         }\r
+\r
+\r
         // --- execute search\r
         TopGroupsWithMaxScore topDocsResultSet = multiSearch.executeSearch(pageSize, pageNumber);\r
 \r
@@ -1953,7 +2117,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      */\r
     protected Query createByDistributionJoinQuery(\r
             List<NamedArea> namedAreaList,\r
-            List<PresenceAbsenceTermBase<?>> distributionStatusList,\r
+            List<PresenceAbsenceTerm> distributionStatusList,\r
             QueryFactory queryFactory\r
             ) throws IOException {\r
 \r
@@ -1974,7 +2138,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * @return\r
      */\r
     private BooleanQuery createByDistributionQuery(List<NamedArea> namedAreaList,\r
-            List<PresenceAbsenceTermBase<?>> distributionStatusList, QueryFactory queryFactory) {\r
+            List<PresenceAbsenceTerm> distributionStatusList, QueryFactory queryFactory) {\r
         BooleanQuery areaQuery = new BooleanQuery();\r
         // area field from Distribution\r
         areaQuery.add(queryFactory.newEntityIdsQuery("area.id", namedAreaList), Occur.MUST);\r
@@ -2000,7 +2164,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * @throws IOException\r
      */\r
     protected LuceneSearch prepareByDistributionSearch(\r
-            List<NamedArea> namedAreaList, List<PresenceAbsenceTermBase<?>> distributionStatusList,\r
+            List<NamedArea> namedAreaList, List<PresenceAbsenceTerm> distributionStatusList,\r
             Classification classification) throws IOException {\r
 \r
         BooleanQuery finalQuery = new BooleanQuery();\r
@@ -2066,7 +2230,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException, LuceneMultiSearchException {\r
 \r
         LuceneSearch luceneSearchByDescriptionElement = prepareByDescriptionElementFullTextSearch(null, queryString, classification, null, languages, highlightFragments);\r
-        LuceneSearch luceneSearchByTaxonBase = prepareFindByFullTextSearch(null, queryString, classification, languages, highlightFragments);\r
+        LuceneSearch luceneSearchByTaxonBase = prepareFindByFullTextSearch(null, queryString, classification, languages, highlightFragments, null);\r
 \r
         LuceneMultiSearch multiSearch = new LuceneMultiSearch(luceneIndexToolProvider, luceneSearchByDescriptionElement, luceneSearchByTaxonBase);\r
 \r
@@ -2236,7 +2400,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         }\r
         String genusOfTaxon = taxonName.getGenusOrUninomial();\r
         Set<TaxonNode> nodes = taxon.getTaxonNodes();\r
-         List<String> taxonNames = new ArrayList<String>();\r
+        List<String> taxonNames = new ArrayList<String>();\r
 \r
         for (TaxonNode node: nodes){\r
            // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName\r
@@ -2589,8 +2753,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             potentialCombination.addSource(originalSource);\r
         }\r
 \r
-        inferredSynName.generateTitle();\r
-\r
         return potentialCombination;\r
     }\r
 \r
@@ -2669,9 +2831,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_GENUS_OF());\r
 \r
-        inferredSynName.generateTitle();\r
-\r
-\r
         return inferredGenus;\r
     }\r
 \r
@@ -2766,7 +2925,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_EPITHET_OF());\r
 \r
-        inferredSynName.generateTitle();\r
         return inferredEpithet;\r
     }\r
 \r
@@ -2846,9 +3004,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         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
@@ -2877,9 +3032,291 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return list;\r
     }\r
 \r
+    @Override\r
+    public Synonym changeRelatedTaxonToSynonym(Taxon fromTaxon, Taxon toTaxon, TaxonRelationshipType oldRelationshipType,\r
+            SynonymRelationshipType synonymRelationshipType) throws DataChangeNoRollbackException {\r
+        // Create new synonym using concept name\r
+                TaxonNameBase<?, ?> synonymName = fromTaxon.getName();\r
+                Synonym synonym = Synonym.NewInstance(synonymName, fromTaxon.getSec());\r
+\r
+                // Remove concept relation from taxon\r
+                toTaxon.removeTaxon(fromTaxon, oldRelationshipType);\r
+\r
+\r
+\r
+\r
+                // Create a new synonym for the taxon\r
+                SynonymRelationship synonymRelationship;\r
+                if (synonymRelationshipType != null\r
+                        && synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){\r
+                    synonymRelationship = toTaxon.addHomotypicSynonym(synonym, null, null);\r
+                } else{\r
+                    synonymRelationship = toTaxon.addHeterotypicSynonymName(synonymName);\r
+                }\r
+\r
+                this.saveOrUpdate(toTaxon);\r
+                //TODO: configurator and classification\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 DeleteResult isDeletable(TaxonBase taxonBase, DeleteConfiguratorBase config){\r
+        DeleteResult result = new DeleteResult();\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 DeleteResult isDeletableForSynonym(Set<CdmBase> references, SynonymDeletionConfigurator config){\r
+        String message;\r
+        DeleteResult result = new DeleteResult();\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.addException(new ReferencedObjectUndeletableException(message));\r
+                result.addRelatedObject(ref);\r
+                result.setAbort();\r
+            }\r
+        }\r
+\r
+        return result;\r
+    }\r
+    private DeleteResult isDeletableForTaxon(Set<CdmBase> references, TaxonDeletionConfigurator config){\r
+        String message = null;\r
+        DeleteResult result = new DeleteResult();\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
+\r
+                }\r
+                if (!config.isDeleteDescriptions() && (ref instanceof DescriptionBase)){\r
+                    message = "The Taxon can't be deleted as long as it has factual data.";\r
+\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
+\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
+\r
+                    } else{\r
+                        message = "The Taxon can't be deleted as long as it belongs to a taxon node.";\r
+\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
+\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
+\r
+\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 (ref.isInstanceOf(TaxonInteraction.class)){\r
+                    message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2";\r
+\r
+                }\r
+\r
+              //TaxonInteraction\r
+                if (ref.isInstanceOf(DeterminationEvent.class)){\r
+                    message = "Taxon can't be deleted as it is used in a determination event";\r
+\r
+                }\r
+\r
+            }\r
+            if (message != null){\r
+                   result.addException(new ReferencedObjectUndeletableException(message));\r
+                   result.addRelatedObject(ref);\r
+                   result.setAbort();\r
+            }\r
+        }\r
+\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    public IncludedTaxaDTO listIncludedTaxa(UUID taxonUuid, IncludedTaxonConfiguration config) {\r
+        IncludedTaxaDTO result = new IncludedTaxaDTO(taxonUuid);\r
+\r
+        //preliminary implementation\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
+        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
+        return result;\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
 \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
+       @Override\r
+       @Transactional(readOnly = true)\r
+       public <S extends TaxonBase> Pager<FindByIdentifierDTO<S>> findByIdentifier(\r
+                       Class<S> clazz, String identifier, DefinedTerm identifierType, TaxonNode subtreeFilter,\r
+                       MatchMode matchmode, boolean includeEntity, Integer pageSize,\r
+                       Integer pageNumber,     List<String> propertyPaths) {\r
+               if (subtreeFilter == null){\r
+                       return findByIdentifier(clazz, identifier, identifierType, matchmode, includeEntity, pageSize, pageNumber, propertyPaths);\r
+               }\r
+               \r
+               Integer numberOfResults = dao.countByIdentifier(clazz, identifier, identifierType, subtreeFilter, matchmode);\r
+        List<Object[]> daoResults = new ArrayList<Object[]>();\r
+        if(numberOfResults > 0) { // no point checking again\r
+               daoResults = dao.findByIdentifier(clazz, identifier, identifierType, subtreeFilter,\r
+                               matchmode, includeEntity, pageSize, pageNumber, propertyPaths);\r
+        }\r
+        \r
+        List<FindByIdentifierDTO<S>> result = new ArrayList<FindByIdentifierDTO<S>>();\r
+        for (Object[] daoObj : daoResults){\r
+               if (includeEntity){\r
+                       result.add(new FindByIdentifierDTO<S>((DefinedTerm)daoObj[0], (String)daoObj[1], (S)daoObj[2]));\r
+               }else{\r
+                       result.add(new FindByIdentifierDTO<S>((DefinedTerm)daoObj[0], (String)daoObj[1], (UUID)daoObj[2], (String)daoObj[3]));  \r
+               }\r
+        }\r
+               return new DefaultPagerImpl<FindByIdentifierDTO<S>>(pageNumber, numberOfResults, pageSize, result);\r
+       }\r
 \r
 }\r