Add find method which can be filtered to update editor session
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonServiceImpl.java
index 51a3e94371b77d5554a52adff1f153ca4ad3d769..dc24660dd1bc26c1a500e426a40b8f1149ce447a 100644 (file)
@@ -23,6 +23,7 @@ import java.util.UUID;
 \r
 import javax.persistence.EntityNotFoundException;\r
 \r
+import org.apache.commons.lang.StringUtils;\r
 import org.apache.log4j.Logger;\r
 import org.apache.lucene.index.CorruptIndexException;\r
 import org.apache.lucene.queryParser.ParseException;\r
@@ -67,6 +68,8 @@ import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseClassBridge;
 import eu.etaxonomy.cdm.hibernate.search.GroupByTaxonClassBridge;\r
 import eu.etaxonomy.cdm.hibernate.search.MultilanguageTextFieldBridge;\r
 import eu.etaxonomy.cdm.model.CdmBaseType;\r
+import eu.etaxonomy.cdm.model.common.Annotation;\r
+import eu.etaxonomy.cdm.model.common.AnnotationType;\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
@@ -76,7 +79,6 @@ import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
 import eu.etaxonomy.cdm.model.common.OriginalSourceType;\r
 import eu.etaxonomy.cdm.model.common.RelationshipBase;\r
 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;\r
-import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;\r
 import eu.etaxonomy.cdm.model.description.CommonTaxonName;\r
 import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
@@ -123,6 +125,7 @@ import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
 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.dto.UuidAndTitleCache;\r
 import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;\r
 import eu.etaxonomy.cdm.persistence.query.MatchMode;\r
 import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
@@ -232,16 +235,10 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return taxonRelTypeVocabulary;\r
     }\r
 \r
-\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)\r
-     */\r
     @Override\r
     @Transactional(readOnly = false)\r
-    public void swapSynonymAndAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon){\r
-\r
+    public UpdateResult swapSynonymAndAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon){\r
+       UpdateResult result = new UpdateResult();\r
         TaxonNameBase<?,?> synonymName = synonym.getName();\r
         synonymName.removeTaxonBase(synonym);\r
         TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();\r
@@ -249,6 +246,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         synonym.setName(taxonName);\r
         acceptedTaxon.setName(synonymName);\r
+        result.addUpdatedObject(acceptedTaxon);\r
+        result.addUpdatedObject(synonym);\r
+               return result;\r
 \r
         // the accepted taxon needs a new uuid because the concept has changed\r
         // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"\r
@@ -256,10 +256,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     }\r
 \r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)\r
-     */\r
-\r
     @Override\r
     @Transactional(readOnly = false)\r
     public Taxon changeSynonymToAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon, boolean deleteSynonym, boolean copyCitationInfo, Reference citation, String microCitation) throws HomotypicalGroupChangeException{\r
@@ -308,8 +304,39 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return newAcceptedTaxon;\r
     }\r
 \r
+    @Override\r
+    @Transactional(readOnly = false)\r
+    public Taxon changeSynonymToAcceptedTaxon(UUID synonymUuid,\r
+            UUID acceptedTaxonUuid,\r
+            boolean deleteSynonym,\r
+            boolean copyCitationInfo,\r
+            Reference citation,\r
+            String microCitation) throws HomotypicalGroupChangeException {\r
+        Synonym synonym = CdmBase.deproxy(dao.load(synonymUuid), Synonym.class);\r
+        Taxon acceptedTaxon = CdmBase.deproxy(dao.load(acceptedTaxonUuid), Taxon.class);\r
+        return changeSynonymToAcceptedTaxon(synonym, acceptedTaxon, deleteSynonym, copyCitationInfo, citation, microCitation);\r
+    }\r
 \r
     @Override\r
+    @Transactional(readOnly = false)\r
+    public UpdateResult changeSynonymToRelatedTaxon(UUID synonymUuid,\r
+            UUID toTaxonUuid,\r
+            TaxonRelationshipType taxonRelationshipType,\r
+            Reference citation,\r
+            String microcitation){\r
+\r
+        UpdateResult result = new UpdateResult();\r
+        Taxon toTaxon = (Taxon) dao.load(toTaxonUuid);\r
+        Synonym synonym = (Synonym) dao.load(synonymUuid);\r
+        Taxon relatedTaxon = changeSynonymToRelatedTaxon(synonym, toTaxon, taxonRelationshipType, citation, microcitation);\r
+        result.setCdmEntity(relatedTaxon);\r
+        result.addUpdatedObject(relatedTaxon);\r
+        result.addUpdatedObject(toTaxon);\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    @Transactional(readOnly = false)\r
     public Taxon changeSynonymToRelatedTaxon(Synonym synonym, Taxon toTaxon, TaxonRelationshipType taxonRelationshipType, Reference citation, String microcitation){\r
 \r
         // Get name from synonym\r
@@ -332,10 +359,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return fromTaxon;\r
     }\r
 \r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeHomotypicalGroupOfSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.name.HomotypicalGroup, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)\r
-     */\r
     @Transactional(readOnly = false)\r
     @Override\r
     public void changeHomotypicalGroupOfSynonym(Synonym synonym, HomotypicalGroup newHomotypicalGroup, Taxon targetTaxon,\r
@@ -396,10 +419,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
     }\r
 \r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)\r
-     */\r
     @Override\r
     @Transactional(readOnly = false)\r
     public void updateTitleCache(Class<? extends TaxonBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<TaxonBase> cacheStrategy, IProgressMonitor monitor) {\r
@@ -598,9 +617,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return taxa;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-     */\r
     @Override\r
     public Pager<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
         Integer numberOfResults = dao.countSynonyms(taxon, type);\r
@@ -613,9 +629,6 @@ 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#getSynonyms(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-     */\r
     @Override\r
     public Pager<SynonymRelationship> getSynonyms(Synonym synonym,     SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
         Integer numberOfResults = dao.countSynonyms(synonym, type);\r
@@ -628,9 +641,6 @@ 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
@@ -649,18 +659,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \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<Synonym> getHomotypicSynonymsByHomotypicGroup(Taxon taxon, List<String> propertyPaths){\r
         Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);\r
         return t.getHomotypicSynonymsByHomotypicGroup();\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)\r
-     */\r
     @Override\r
     public List<List<Synonym>> getHeterotypicSynonymyGroups(Taxon taxon, List<String> propertyPaths){\r
         Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);\r
@@ -692,9 +696,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return results;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)\r
-     */\r
     @Override\r
     public Pager<IdentifiableEntity> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator) {\r
 \r
@@ -783,9 +784,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return dao.getUuidAndTitleCache();\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])\r
-     */\r
     @Override\r
     public List<MediaRepresentation> getAllMedia(Taxon taxon, int size, int height, int widthOrDuration, String[] mimeTypes){\r
         List<MediaRepresentation> medRep = new ArrayList<MediaRepresentation>();\r
@@ -805,23 +803,19 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return medRep;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)\r
-     */\r
     @Override\r
     public List<Media> listTaxonDescriptionMedia(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships, boolean limitToGalleries, List<String> propertyPath){\r
         return listMedia(taxon, includeRelationships, limitToGalleries, true, false, false, propertyPath);\r
     }\r
 \r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)\r
-     */\r
     @Override\r
     public List<Media> listMedia(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships,\r
             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
@@ -948,52 +942,35 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return taxonMedia;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)\r
-     */\r
     @Override\r
     public List<TaxonBase> findTaxaByID(Set<Integer> listOfIDs) {\r
         return this.dao.listByIds(listOfIDs, null, null, null, null);\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)\r
-     */\r
     @Override\r
     public TaxonBase findTaxonByUuid(UUID uuid, List<String> propertyPaths){\r
         return this.dao.findByUuid(uuid, null ,propertyPaths);\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()\r
-     */\r
     @Override\r
     public int countAllRelationships() {\r
         return this.dao.countAllRelationships();\r
     }\r
 \r
-\r
-\r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)\r
-     */\r
     @Override\r
     public List<TaxonNameBase> findIdenticalTaxonNames(List<String> propertyPath) {\r
         return this.dao.findIdenticalTaxonNames(propertyPath);\r
     }\r
 \r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)\r
-     */\r
     @Override\r
-    public DeleteResult deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config, Classification classification)  {\r
+    @Transactional(readOnly = false)\r
+    public DeleteResult deleteTaxon(UUID taxonUUID, TaxonDeletionConfigurator config, UUID classificationUuid)  {\r
 \r
        if (config == null){\r
             config = new TaxonDeletionConfigurator();\r
         }\r
-\r
+       Taxon taxon = (Taxon)dao.load(taxonUUID);\r
+       Classification classification = HibernateProxyHelper.deproxy(classificationDao.load(classificationUuid), Classification.class);\r
         DeleteResult result = isDeletable(taxon, config);\r
 \r
         if (result.isOk()){\r
@@ -1038,7 +1015,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                     if (config.isDeleteMisappliedNamesAndInvalidDesignations()){\r
                         if (taxRel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR()) || taxRel.getType().equals(TaxonRelationshipType.INVALID_DESIGNATION_FOR())){\r
                             if (taxon.equals(taxRel.getToTaxon())){\r
-                                this.deleteTaxon(taxRel.getFromTaxon(), config, classification);\r
+\r
+                                this.deleteTaxon(taxRel.getFromTaxon().getUuid(), config, classificationUuid);\r
                             }\r
                         }\r
                     }\r
@@ -1073,11 +1051,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                         //throw new ReferencedObjectUndeletableException(message);\r
                     }\r
                     removeDescriptions.add(desc);\r
-                    descriptionService.delete(desc);\r
+\r
 \r
                 }\r
                 for (TaxonDescription desc: removeDescriptions){\r
                     taxon.removeDescription(desc);\r
+                    descriptionService.delete(desc);\r
                 }\r
             }\r
 \r
@@ -1187,10 +1166,10 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
                         //remove name if possible (and required)\r
                         if (name != null && config.isDeleteNameIfPossible()){\r
-                               nameResult = nameService.delete(name, config.getNameDeletionConfig());\r
+                               nameResult = nameService.delete(name.getUuid(), config.getNameDeletionConfig());\r
                         }\r
-                        \r
-                        if (nameResult.isError()){\r
+\r
+                        if (nameResult.isError() || nameResult.isAbort()){\r
                                //result.setError();\r
                                result.addRelatedObject(name);\r
                                result.addExceptions(nameResult.getExceptions());\r
@@ -1291,29 +1270,30 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return result;\r
     }\r
 \r
+    @Override\r
     @Transactional(readOnly = false)\r
-    public UUID delete(Synonym syn){\r
-        UUID result = syn.getUuid();\r
-        this.deleteSynonym(syn, null);\r
-        return result;\r
-    }\r
+    public DeleteResult delete(UUID synUUID){\r
+       DeleteResult result = new DeleteResult();\r
+       Synonym syn = (Synonym)dao.load(synUUID);\r
 \r
+        return this.deleteSynonym(syn, null);\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
+    @Transactional(readOnly = false)\r
     public DeleteResult deleteSynonym(Synonym synonym, SynonymDeletionConfigurator config) {\r
         return deleteSynonym(synonym, null, config);\r
 \r
     }\r
 \r
+    @Override\r
+    @Transactional(readOnly = false)\r
+    public DeleteResult deleteSynonym(UUID synonymUuid, SynonymDeletionConfigurator config) {\r
+        return deleteSynonym((Synonym)dao.load(synonymUuid), config);\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 DeleteResult deleteSynonym(Synonym synonym, Taxon taxon, SynonymDeletionConfigurator config) {\r
@@ -1330,6 +1310,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
 \r
         if (result.isOk()){\r
+\r
             synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);\r
 \r
             //remove synonymRelationship\r
@@ -1350,6 +1331,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
             //remove synonym (if necessary)\r
 \r
+            result.addUpdatedObject(taxon);\r
             if (synonym.getSynonymRelations().isEmpty()){\r
                 TaxonNameBase<?,?> name = synonym.getName();\r
                 synonym.setName(null);\r
@@ -1358,7 +1340,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 //remove name if possible (and required)\r
                 if (name != null && config.isDeleteNameIfPossible()){\r
 \r
-                        DeleteResult nameDeleteresult = nameService.delete(name, config.getNameDeletionConfig());\r
+                        DeleteResult nameDeleteresult = nameService.delete(name.getUuid(), config.getNameDeletionConfig());\r
                         if (nameDeleteresult.isAbort()){\r
                                result.addExceptions(nameDeleteresult.getExceptions());\r
                                result.addUpdatedObject(name);\r
@@ -1388,44 +1370,27 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
     }\r
 \r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)\r
-     */\r
     @Override\r
     public List<TaxonNameBase> findIdenticalTaxonNameIds(List<String> propertyPath) {\r
 \r
         return this.dao.findIdenticalNamesNew(propertyPath);\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)\r
-     */\r
     @Override\r
     public String getPhylumName(TaxonNameBase name){\r
         return this.dao.getPhylumName(name);\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)\r
-     */\r
     @Override\r
     public long deleteSynonymRelationships(Synonym syn, Taxon taxon) {\r
         return dao.deleteSynonymRelationships(syn, taxon);\r
     }\r
 \r
-/* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)\r
-     */\r
     @Override\r
     public long deleteSynonymRelationships(Synonym syn) {\r
         return dao.deleteSynonymRelationships(syn, null);\r
     }\r
 \r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listSynonymRelationships(eu.etaxonomy.cdm.model.taxon.TaxonBase, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List, eu.etaxonomy.cdm.model.common.RelationshipBase.Direction)\r
-     */\r
     @Override\r
     public List<SynonymRelationship> listSynonymRelationships(\r
             TaxonBase taxonBase, SynonymRelationshipType type, Integer pageSize, Integer pageNumber,\r
@@ -1439,9 +1404,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return results;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)\r
-     */\r
     @Override\r
     public Taxon findBestMatchingTaxon(String taxonName) {\r
         MatchingTaxonConfigurator config = MatchingTaxonConfigurator.NewInstance();\r
@@ -1449,8 +1411,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return findBestMatchingTaxon(config);\r
     }\r
 \r
-\r
-\r
     @Override\r
     public Taxon findBestMatchingTaxon(MatchingTaxonConfigurator config) {\r
 \r
@@ -1559,9 +1519,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return configSecUuid.equals(taxonSecUuid);\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)\r
-     */\r
     @Override\r
     public Synonym findBestMatchingSynonym(String taxonName) {\r
         List<TaxonBase> synonymList = dao.findByNameTitleCache(false, true, taxonName, null, MatchMode.EXACT, null, 0, null, null);\r
@@ -1578,16 +1535,18 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return null;\r
     }\r
 \r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#moveSynonymToAnotherTaxon(eu.etaxonomy.cdm.model.taxon.SynonymRelationship, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, eu.etaxonomy.cdm.model.reference.Reference, java.lang.String, boolean)\r
-     */\r
     @Override\r
-    public SynonymRelationship moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation, Taxon newTaxon, boolean moveHomotypicGroup,\r
-            SynonymRelationshipType newSynonymRelationshipType, Reference reference, String referenceDetail, boolean keepReference) throws HomotypicalGroupChangeException {\r
-\r
-        Synonym synonym = oldSynonymRelation.getSynonym();\r
-        Taxon fromTaxon = oldSynonymRelation.getAcceptedTaxon();\r
+    @Transactional(readOnly = false)\r
+    public SynonymRelationship moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation,\r
+            Taxon newTaxon,\r
+            boolean moveHomotypicGroup,\r
+            SynonymRelationshipType newSynonymRelationshipType,\r
+            Reference reference,\r
+            String referenceDetail,\r
+            boolean keepReference) throws HomotypicalGroupChangeException {\r
+\r
+        Synonym synonym = (Synonym) dao.load(oldSynonymRelation.getSynonym().getUuid());\r
+        Taxon fromTaxon = (Taxon) dao.load(oldSynonymRelation.getAcceptedTaxon().getUuid());\r
         //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)\r
         TaxonNameBase<?,?> synonymName = synonym.getName();\r
         TaxonNameBase<?,?> fromTaxonName = fromTaxon.getName();\r
@@ -1661,25 +1620,16 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return result;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()\r
-     */\r
     @Override\r
     public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheTaxon() {\r
         return dao.getUuidAndTitleCacheTaxon();\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()\r
-     */\r
     @Override\r
     public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheSynonym() {\r
         return dao.getUuidAndTitleCacheSynonym();\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-     */\r
     @Override\r
     public Pager<SearchResult<TaxonBase>> findByFullText(\r
             Class<? extends TaxonBase> clazz, String queryString,\r
@@ -1753,10 +1703,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
@@ -1837,12 +1792,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return luceneSearch;\r
     }\r
 \r
-\r
-\r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNamesByFullText(java.util.EnumSet, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.Set, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.Map)\r
-     */\r
     @Override\r
     public Pager<SearchResult<TaxonBase>> findTaxaAndNamesByFullText(\r
             EnumSet<TaxaAndNamesSearchMode> searchModes, String queryString, Classification classification,\r
@@ -2192,11 +2141,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return luceneSearch;\r
     }\r
 \r
-\r
-\r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByDescriptionElementFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-     */\r
     @Override\r
     public Pager<SearchResult<TaxonBase>> findByDescriptionElementFullText(\r
             Class<? extends DescriptionElementBase> clazz, String queryString,\r
@@ -3033,6 +2977,25 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     }\r
 \r
     @Override\r
+    @Transactional(readOnly = false)\r
+    public UpdateResult changeRelatedTaxonToSynonym(UUID fromTaxonUuid,\r
+            UUID toTaxonUuid,\r
+            TaxonRelationshipType oldRelationshipType,\r
+            SynonymRelationshipType synonymRelationshipType) throws DataChangeNoRollbackException {\r
+        UpdateResult result = new UpdateResult();\r
+        Taxon fromTaxon = (Taxon) dao.load(fromTaxonUuid);\r
+        Taxon toTaxon = (Taxon) dao.load(toTaxonUuid);\r
+        Synonym synonym = changeRelatedTaxonToSynonym(fromTaxon, toTaxon, oldRelationshipType, synonymRelationshipType);\r
+        result.setCdmEntity(synonym);\r
+        result.addUpdatedObject(fromTaxon);\r
+        result.addUpdatedObject(toTaxon);\r
+        result.addUpdatedObject(synonym);\r
+\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    @Transactional(readOnly = false)\r
     public Synonym changeRelatedTaxonToSynonym(Taxon fromTaxon, Taxon toTaxon, TaxonRelationshipType oldRelationshipType,\r
             SynonymRelationshipType synonymRelationshipType) throws DataChangeNoRollbackException {\r
         // Create new synonym using concept name\r
@@ -3058,10 +3021,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 //TODO: configurator and classification\r
                 TaxonDeletionConfigurator config = new TaxonDeletionConfigurator();\r
                 config.setDeleteNameIfPossible(false);\r
-                this.deleteTaxon(fromTaxon, config, null);\r
+                this.deleteTaxon(fromTaxon.getUuid(), config, null);\r
                 return synonymRelationship.getSynonym();\r
 \r
     }\r
+\r
     @Override\r
     public DeleteResult isDeletable(TaxonBase taxonBase, DeleteConfiguratorBase config){\r
         DeleteResult result = new DeleteResult();\r
@@ -3090,11 +3054,13 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         return result;\r
     }\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
+               message = null;\r
                 if (!config.isDeleteSynonymRelations() && (ref instanceof SynonymRelationship)){\r
                     message = "The Taxon can't be deleted as long as it has synonyms.";\r
 \r
@@ -3211,7 +3177,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         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
+                List<TaxonNode> childNodes = nodeService.loadChildNodesOfTaxonNode(node, null, true, null);\r
                 for (TaxonNode child : childNodes){\r
                     children.add(child.getTaxon());\r
                 }\r
@@ -3290,7 +3256,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         List<TaxonBase> taxonList = dao.getTaxaByName(true, false, false, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, 0, config.getPropertyPath());\r
         return taxonList;\r
     }\r
-    \r
+\r
        @Override\r
        @Transactional(readOnly = true)\r
        public <S extends TaxonBase> Pager<FindByIdentifierDTO<S>> findByIdentifier(\r
@@ -3300,30 +3266,95 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                if (subtreeFilter == null){\r
                        return findByIdentifier(clazz, identifier, identifierType, matchmode, includeEntity, pageSize, pageNumber, propertyPaths);\r
                }\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
+\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
+                       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
+       @Transactional(readOnly = false)\r
+       public UpdateResult moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation, UUID newTaxonUUID, boolean moveHomotypicGroup,\r
             SynonymRelationshipType newSynonymRelationshipType, Reference reference, String referenceDetail, boolean keepReference) throws HomotypicalGroupChangeException {\r
-               \r
+\r
+           UpdateResult result = new UpdateResult();\r
                Taxon newTaxon = (Taxon) dao.load(newTaxonUUID);\r
-               return moveSynonymToAnotherTaxon(oldSynonymRelation, newTaxon, moveHomotypicGroup, newSynonymRelationshipType, reference, referenceDetail, keepReference);\r
+               SynonymRelationship sr = moveSynonymToAnotherTaxon(oldSynonymRelation, newTaxon, moveHomotypicGroup, newSynonymRelationshipType, reference, referenceDetail, keepReference);\r
+               result.setCdmEntity(sr);\r
+               result.addUpdatedObject(sr);\r
+               result.addUpdatedObject(newTaxon);\r
+               return result;\r
        }\r
+\r
+       @Override\r
+       public UpdateResult moveFactualDateToAnotherTaxon(UUID fromTaxonUuid, UUID toTaxonUuid){\r
+               UpdateResult result = new UpdateResult();\r
+\r
+               Taxon fromTaxon = (Taxon)dao.load(fromTaxonUuid);\r
+               Taxon toTaxon = (Taxon) dao.load(toTaxonUuid);\r
+                 for(TaxonDescription description : fromTaxon.getDescriptions()){\r
+              //reload to avoid session conflicts\r
+              description = HibernateProxyHelper.deproxy(description, TaxonDescription.class);\r
+\r
+              String moveMessage = String.format("Description moved from %s", fromTaxon);\r
+              if(description.isProtectedTitleCache()){\r
+                  String separator = "";\r
+                  if(!StringUtils.isBlank(description.getTitleCache())){\r
+                      separator = " - ";\r
+                  }\r
+                  description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);\r
+              }\r
+              Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());\r
+              annotation.setAnnotationType(AnnotationType.TECHNICAL());\r
+              description.addAnnotation(annotation);\r
+              toTaxon.addDescription(description);\r
+              dao.saveOrUpdate(toTaxon);\r
+              dao.saveOrUpdate(fromTaxon);\r
+              result.addUpdatedObject(toTaxon);\r
+              result.addUpdatedObject(fromTaxon);\r
+\r
+          }\r
+\r
+\r
+               return result;\r
+       }\r
+\r
+       @Override\r
+       public DeleteResult deleteSynonym(UUID synonymUuid, UUID taxonUuid,\r
+                       SynonymDeletionConfigurator config) {\r
+               TaxonBase base = this.load(synonymUuid);\r
+               Synonym syn = HibernateProxyHelper.deproxy(base, Synonym.class);\r
+               base = this.load(taxonUuid);\r
+               Taxon taxon = HibernateProxyHelper.deproxy(base, Taxon.class);\r
+\r
+               return this.deleteSynonym(syn, taxon, config);\r
+       }\r
+\r
+       @Override\r
+       @Transactional(readOnly = false)\r
+       public UpdateResult swapSynonymAndAcceptedTaxon(UUID synonymUUid,\r
+                       UUID acceptedTaxonUuid) {\r
+               TaxonBase base = this.load(synonymUUid);\r
+               Synonym syn = HibernateProxyHelper.deproxy(base, Synonym.class);\r
+               base = this.load(acceptedTaxonUuid);\r
+               Taxon taxon = HibernateProxyHelper.deproxy(base, Taxon.class);\r
+\r
+               return this.swapSynonymAndAcceptedTaxon(syn, taxon);\r
+       }\r
+\r
+\r
+\r
 }\r