fixing #4179 (improve performance of portal/taxon/{uuid}/media)
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonServiceImpl.java
index 229956a3a3faec9d0b14002e8ab48322b3bf4267..75566cc5a3be1cc00daeb00d0e0fdaae2d2ef646 100644 (file)
@@ -44,9 +44,11 @@ import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;
 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
 import eu.etaxonomy.cdm.api.service.pager.Pager;\r
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
 import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;\r
@@ -66,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
@@ -81,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
@@ -90,7 +93,7 @@ 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
@@ -343,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
@@ -412,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
@@ -427,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
@@ -442,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
@@ -456,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
@@ -470,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
@@ -484,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
@@ -542,15 +527,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     }\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 Set<Taxon> listRelatedTaxa(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships, Integer maxDepth,\r
             Integer limit, Integer start, List<String> propertyPaths) {\r
@@ -697,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
@@ -848,10 +822,14 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             Boolean limitToGalleries, Boolean includeTaxonDescriptions, Boolean includeOccurrences,\r
             Boolean includeTaxonNameDescriptions, List<String> propertyPath) {\r
 \r
+    //    logger.setLevel(Level.TRACE);\r
+//        Logger.getLogger("org.hibernate.SQL").setLevel(Level.TRACE);\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
@@ -876,11 +854,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
-                            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
@@ -926,7 +911,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
@@ -1006,14 +991,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 String deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config, Classification classification)  {\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
-        List<String> referencedObjects = isDeletable(taxon, config);\r
+        DeleteResult result = isDeletable(taxon, config);\r
 \r
-        if (referencedObjects.isEmpty()){\r
+        if (result.isOk()){\r
             // --- DeleteSynonymRelations\r
             if (config.isDeleteSynonymRelations()){\r
                 boolean removeSynonymNameFromHomotypicalGroup = false;\r
@@ -1134,8 +1120,8 @@ 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
                         Set<ITaxonTreeNode> nodesList = new HashSet<ITaxonTreeNode>();\r
@@ -1170,11 +1156,15 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                                 }\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
-                        // 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
@@ -1182,7 +1172,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
              //PolytomousKey TODO\r
 \r
-             boolean usedInPolytomousKey = checkForPolytomousKeys(taxon);\r
+\r
             //TaxonNameBase\r
             if (config.isDeleteNameIfPossible()){\r
 \r
@@ -1192,10 +1182,23 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                     //check whether taxon will be deleted or not\r
                     if ((taxon.getTaxonNodes() == null || taxon.getTaxonNodes().size()== 0) && name != null ){\r
                         taxon = (Taxon) HibernateProxyHelper.deproxy(taxon);\r
-                        name.removeTaxonBase(taxon);\r
-                        nameService.merge(name);\r
-                        String uuidString = nameService.delete(name, config.getNameDeletionConfig());\r
-                        logger.debug(uuidString);\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
 \r
             }\r
@@ -1219,15 +1222,31 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 }*/\r
 \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
-                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
-             return referencedObjects.toString();\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
@@ -1282,12 +1301,14 @@ 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 String deleteSynonym(Synonym synonym, SynonymDeletionConfigurator config) {\r
+    public DeleteResult deleteSynonym(Synonym synonym, SynonymDeletionConfigurator config) {\r
         return deleteSynonym(synonym, null, config);\r
 \r
     }\r
@@ -1298,16 +1319,20 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      */\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
         if (config == null){\r
             config = new SynonymDeletionConfigurator();\r
         }\r
-        List<String> messages = isDeletable(synonym, config);\r
-        if (messages.isEmpty()){\r
+        result = isDeletable(synonym, config);\r
+\r
+\r
+        if (result.isOk()){\r
             synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);\r
 \r
             //remove synonymRelationship\r
@@ -1318,8 +1343,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 taxonSet.addAll(synonym.getAcceptedTaxa());\r
             }\r
             for (Taxon relatedTaxon : taxonSet){\r
-    //                 dao.deleteSynonymRelationships(synonym, relatedTaxon);\r
-                relatedTaxon.removeSynonym(synonym, config.isNewHomotypicGroupIfNeeded());\r
+               relatedTaxon = HibernateProxyHelper.deproxy(relatedTaxon, Taxon.class);\r
+                relatedTaxon.removeSynonym(synonym, false);\r
+                this.saveOrUpdate(relatedTaxon);\r
             }\r
             this.saveOrUpdate(synonym);\r
 \r
@@ -1327,26 +1353,40 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \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
+                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
+                        DeleteResult nameDeleteresult = nameService.delete(name, config.getNameDeletionConfig());\r
+                        if (nameDeleteresult.isAbort()){\r
+                               result.addExceptions(nameDeleteresult.getExceptions());\r
+                               result.addUpdatedObject(name);\r
+                        }\r
 \r
                 }\r
 \r
             }else {\r
-                return null;\r
+               result.setError();\r
+               result.addException(new ReferencedObjectUndeletableException("Synonym can not be deleted it is used in a synonymRelationship."));\r
+                return result;\r
             }\r
-            return uuid.toString();\r
-        }else{\r
-            return messages.toString();\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
@@ -1597,6 +1637,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
@@ -1612,6 +1654,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
@@ -1665,7 +1708,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
@@ -1713,10 +1756,15 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         // ---- search criteria\r
         luceneSearch.setCdmTypRestriction(clazz);\r
 \r
-        textQuery.add(taxonBaseQueryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
-        textQuery.add(taxonBaseQueryFactory.newDefinedTermQuery("name.rank", queryString, languages), Occur.SHOULD);\r
+        if(!queryString.isEmpty() && !queryString.equals("*") && !queryString.equals("?") ) {\r
+            textQuery.add(taxonBaseQueryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
+            textQuery.add(taxonBaseQueryFactory.newDefinedTermQuery("name.rank", queryString, languages), Occur.SHOULD);\r
+        }\r
+\r
+        if(textQuery.getClauses().length > 0) {\r
+            finalQuery.add(textQuery, Occur.MUST);\r
+        }\r
 \r
-        finalQuery.add(textQuery, Occur.MUST);\r
 \r
         if(classification != null){\r
             finalQuery.add(taxonBaseQueryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST);\r
@@ -1806,7 +1854,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
@@ -1822,13 +1870,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
@@ -2077,7 +2125,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
@@ -2098,7 +2146,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
@@ -2124,7 +2172,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
@@ -3016,14 +3064,16 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \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
-        List<String> result = new ArrayList<String>();\r
-        Set<CdmBase> references = commonService.getReferencingObjects(taxonBase);\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
@@ -3034,53 +3084,55 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return result;\r
     }\r
 \r
-    private List<String> isDeletableForSynonym(Set<CdmBase> references, SynonymDeletionConfigurator config){\r
+    private DeleteResult isDeletableForSynonym(Set<CdmBase> references, SynonymDeletionConfigurator config){\r
         String message;\r
-        List<String> result = new ArrayList<String>();\r
+        DeleteResult result = new DeleteResult();\r
         for (CdmBase ref: references){\r
-            if (!(ref instanceof SynonymRelationship || ref instanceof Taxon || ref instanceof TaxonNameBase)){\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
+                result.addException(new ReferencedObjectUndeletableException(message));\r
+                result.addRelatedObject(ref);\r
+                result.setAbort();\r
             }\r
         }\r
 \r
         return result;\r
     }\r
-    private List<String> isDeletableForTaxon(Set<CdmBase> references, TaxonDeletionConfigurator config){\r
-        String message;\r
-        List<String> result = new ArrayList<String>();\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
-                    result.add(message);\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
-                    result.add(message);\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
-                    result.add(message);\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
-                        result.add(message);\r
+\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
                 }\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
 \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
+\r
 \r
                 }\r
 \r
@@ -3094,17 +3146,21 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 //TaxonInteraction\r
                 if (ref.isInstanceOf(TaxonInteraction.class)){\r
                     message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2";\r
-                    result.add(message);\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
-                    result.add(message);\r
+\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
@@ -3237,6 +3293,45 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         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
+       @Override\r
+       public SynonymRelationship moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation, UUID newTaxonUUID, boolean moveHomotypicGroup,\r
+            SynonymRelationshipType newSynonymRelationshipType, Reference reference, String referenceDetail, boolean keepReference) throws HomotypicalGroupChangeException {\r
 \r
+               Taxon newTaxon = (Taxon) dao.load(newTaxonUUID);\r
+               return moveSynonymToAnotherTaxon(oldSynonymRelation, newTaxon, moveHomotypicGroup, newSynonymRelationshipType, reference, referenceDetail, keepReference);\r
+       }\r
 }\r