Add generic find(clazz, uuid) method #5853
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DescriptionServiceImpl.java
index d11412edbc296ba4d5275d5a5c9bf4a0c3d47a3e..e813dcdc46fb718b0e67a0d3b40983966c2d9e6a 100644 (file)
@@ -18,6 +18,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -28,7 +29,10 @@ import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
 import eu.etaxonomy.cdm.api.utility.DescriptionUtility;
 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
+import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
 import eu.etaxonomy.cdm.model.common.Annotation;
+import eu.etaxonomy.cdm.model.common.AnnotationType;
+import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.common.DefinedTerm;
 import eu.etaxonomy.cdm.model.common.Language;
 import eu.etaxonomy.cdm.model.common.Marker;
@@ -39,7 +43,7 @@ import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
 import eu.etaxonomy.cdm.model.description.Distribution;
 import eu.etaxonomy.cdm.model.description.Feature;
 import eu.etaxonomy.cdm.model.description.FeatureTree;
-import eu.etaxonomy.cdm.model.description.PresenceAbsenceTermBase;
+import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
 import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
 import eu.etaxonomy.cdm.model.description.TextData;
@@ -56,6 +60,8 @@ import eu.etaxonomy.cdm.persistence.dao.description.IFeatureDao;
 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureNodeDao;
 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureTreeDao;
 import eu.etaxonomy.cdm.persistence.dao.description.IStatisticalMeasurementValueDao;
+import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
+import eu.etaxonomy.cdm.persistence.dto.TermDto;
 import eu.etaxonomy.cdm.persistence.query.OrderHint;
 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
 
@@ -82,6 +88,8 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
     protected ITermVocabularyDao vocabularyDao;
     protected IDefinedTermDao definedTermDao;
     protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
+    protected ITaxonDao taxonDao;
+
     //TODO change to Interface
     private NaturalLanguageGenerator naturalLanguageGenerator;
 
@@ -125,6 +133,11 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
         this.naturalLanguageGenerator = naturalLanguageGenerator;
     }
 
+    @Autowired
+    protected void setTaxonDao(ITaxonDao taxonDao) {
+        this.taxonDao = taxonDao;
+    }
+
     /**
      *
      */
@@ -133,10 +146,6 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
     }
 
 
-
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
-     */
     @Override
     @Transactional(readOnly = false)
     public void updateTitleCache(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
@@ -166,42 +175,41 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
     }
 
     @Override
-    public Pager<DescriptionElementBase> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
-            Set<Feature> features, Class<? extends DescriptionElementBase> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
+    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
+            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
 
-        List<DescriptionElementBase> results = listDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
-        return new DefaultPagerImpl<DescriptionElementBase>(pageNumber, results.size(), pageSize, results);
+        List<T> results = listDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
+        return new DefaultPagerImpl<T>(pageNumber, results.size(), pageSize, results);
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#getDescriptionElements(eu.etaxonomy.cdm.model.description.DescriptionBase, java.util.Set, java.lang.Class, java.lang.Integer, java.lang.Integer, java.util.List)
-     */
     @Override
     @Deprecated
-    public Pager<DescriptionElementBase> getDescriptionElements(DescriptionBase description,
-            Set<Feature> features, Class<? extends DescriptionElementBase> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
+    public <T extends DescriptionElementBase> Pager<T> getDescriptionElements(DescriptionBase description,
+            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
         return pageDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
     }
 
+
+
     @Override
-    public List<DescriptionElementBase> listDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
-            Set<Feature> features, Class<? extends DescriptionElementBase> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
+    public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
+            Class<? extends DescriptionBase> descriptionType, Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber,
+            List<String> propertyPaths) {
 
         Integer numberOfResults = dao.countDescriptionElements(description, descriptionType, features, type);
-        List<DescriptionElementBase> results = new ArrayList<DescriptionElementBase>();
-        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
+        List<T> results = new ArrayList<T>();
+        if(AbstractPagerImpl.hasResultsInRange(numberOfResults.longValue(), pageNumber, pageSize)) {
             results = dao.getDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
         }
         return results;
+
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#listDescriptionElements(eu.etaxonomy.cdm.model.description.DescriptionBase, java.util.Set, java.lang.Class, java.lang.Integer, java.lang.Integer, java.util.List)
-     */
+
     @Override
     @Deprecated
-    public List<DescriptionElementBase> listDescriptionElements(DescriptionBase description,
-            Set<Feature> features, Class<? extends DescriptionElementBase> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
+    public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
+            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
 
         return listDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
     }
@@ -219,7 +227,6 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
     }
 
 
-
     @Override
     public Pager<Media> getMedia(DescriptionElementBase descriptionElement,    Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
         Integer numberOfResults = descriptionElementDao.countMedia(descriptionElement);
@@ -244,10 +251,6 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
         return listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
     }
 
-
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#pageMarkedTaxonDescriptions(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, java.util.Set, java.util.Set, java.lang.Integer, java.lang.Integer, java.util.List)
-     */
     @Override
     public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
         Integer numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes);
@@ -267,37 +270,26 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
     }
 
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#listTaxonDescriptionMedia(UUID, boolean, Set, Integer, Integer, List)
-     */
     @Override
     public List<Media> listTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths){
         return this.dao.listTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes, pageSize, pageNumber, propertyPaths);
     }
 
-    /*
-     * @see IDescriptionService#countTaxonDescriptionMedia(UUID, boolean, Set)
-     */
     @Override
     public int countTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes){
         return this.dao.countTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes);
     }
 
-
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#getOrderedDistributions(java.util.Set, boolean, boolean, java.util.Set, java.util.List)
-     */
     @Override
+    @Deprecated
     public DistributionTree getOrderedDistributions(
             Set<TaxonDescription> taxonDescriptions,
             boolean subAreaPreference,
             boolean statusOrderPreference,
-            Set<MarkerType> hideMarkedAreas,
+            Set<MarkerType> hiddenAreaMarkerTypes,
             Set<NamedAreaLevel> omitLevels, List<String> propertyPaths){
 
-        DistributionTree tree = new DistributionTree();
         List<Distribution> distList = new ArrayList<Distribution>();
-        if (logger.isDebugEnabled()){logger.debug("create tree ...");}
 
         List<UUID> uuids = new ArrayList<UUID>();
         for (TaxonDescription taxonDescription : taxonDescriptions) {
@@ -340,19 +332,14 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
         if (logger.isDebugEnabled()){logger.debug("filter tree for " + distList.size() + " distributions ...");}
 
         // filter distributions
-        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distList, subAreaPreference, statusOrderPreference, hideMarkedAreas);
+        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distList, hiddenAreaMarkerTypes, true, statusOrderPreference, false);
         distList.clear();
         distList.addAll(filteredDistributions);
 
-        if (logger.isDebugEnabled()){logger.debug("order tree ...");}
-
-        //order by areas
-        tree.orderAsTree(distList, omitLevels);
-        tree.recursiveSortChildrenByLabel(); // FIXME respect current locale for sorting
-        if (logger.isDebugEnabled()){logger.debug("create tree - DONE");}
-        return tree;
+        return DescriptionUtility.orderDistributions(definedTermDao, omitLevels, distList, hiddenAreaMarkerTypes, null);
     }
 
+
     @Override
     public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonNameBase name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
         Integer numberOfResults = dao.countTaxonNameDescriptions(name);
@@ -383,7 +370,7 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
      * Rename: searchByDistribution
      */
     @Override
-    public Pager<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTermBase presence,        Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+    public Pager<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm presence,    Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
         Integer numberOfResults = dao.countDescriptionByDistribution(namedAreas, presence);
 
         List<TaxonDescription> results = new ArrayList<TaxonDescription>();
@@ -435,7 +422,7 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
     @Override
     @Transactional(readOnly = false)
     public UUID saveDescriptionElement(DescriptionElementBase descriptionElement) {
-        return descriptionElementDao.save(descriptionElement);
+        return descriptionElementDao.save(descriptionElement).getUuid();
     }
 
     /**
@@ -457,6 +444,45 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
         return descriptionElementDao.delete(descriptionElement);
     }
 
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescriptionElement(java.util.UUID)
+     */
+    @Override
+    public UUID deleteDescriptionElement(UUID descriptionElementUuid) {
+        return deleteDescriptionElement(descriptionElementDao.load(descriptionElementUuid));
+    }
+
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult deleteDescription(DescriptionBase description) {
+        DeleteResult deleteResult = new DeleteResult();
+
+       if (description instanceof TaxonDescription){
+               TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
+               Taxon tax = taxDescription.getTaxon();
+               tax.removeDescription(taxDescription, true);
+               dao.delete(description);
+
+            deleteResult.addUpdatedObject(tax);
+            deleteResult.setCdmEntity(tax);
+       }
+
+
+        return deleteResult;
+    }
+
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescription(java.util.UUID)
+     */
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult deleteDescription(UUID descriptionUuid) {
+        return deleteDescription(dao.load(descriptionUuid));
+    }
+
+
     @Override
     public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
         return vocabularyDao.findByUuid(uuid);
@@ -476,7 +502,7 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
             Taxon taxon, Set<Feature> features,
             Class<T> type, Integer pageSize,
             Integer pageNumber, List<String> propertyPaths) {
-        return dao.getDescriptionElementForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
+        return dao.getDescriptionElementForTaxon(taxon.getUuid(), features, type, pageSize, pageNumber, propertyPaths);
     }
 
     @Override
@@ -485,7 +511,7 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
             Class<T> type, Integer pageSize,
             Integer pageNumber, List<String> propertyPaths) {
         if (logger.isDebugEnabled()){logger.debug(" get count ...");}
-        Long count = dao.countDescriptionElementForTaxon(taxon, features, type);
+        Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type);
         List<T> descriptionElements;
         if(AbstractPagerImpl.hasResultsInRange(count, pageNumber, pageSize)){ // no point checking again
             if (logger.isDebugEnabled()){logger.debug(" get list ...");}
@@ -609,24 +635,23 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
         return naturalLanguageDescription.toString();
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#hasStructuredData(eu.etaxonomy.cdm.model.description.DescriptionBase)
-     */
+
     @Override
     public boolean hasStructuredData(DescriptionBase<?> description) {
         return load(description.getUuid()).hasStructuredData();
     }
 
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#moveDescriptionElementsToDescription(java.util.Collection, eu.etaxonomy.cdm.model.description.DescriptionBase, boolean)
-     */
     @Override
-    public void moveDescriptionElementsToDescription(Collection<DescriptionElementBase> descriptionElements,
-                                                    DescriptionBase targetDescription, boolean isCopy) {
+    @Transactional(readOnly = false)
+    public UpdateResult moveDescriptionElementsToDescription(
+            Collection<DescriptionElementBase> descriptionElements,
+            DescriptionBase targetDescription,
+            boolean isCopy) {
 
+        UpdateResult result = new UpdateResult();
         if (descriptionElements.isEmpty() ){
-            return ;
+            return result;
         }
 
         if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
@@ -636,27 +661,147 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
 //                     descriptionElements = descriptionElementsTmp;
         }
         for (DescriptionElementBase element : descriptionElements){
-            DescriptionBase description = element.getInDescription();
+            DescriptionBase<?> description = element.getInDescription();
             try {
                 DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
                 targetDescription.addElement(newElement);
             } catch (CloneNotSupportedException e) {
-                new RuntimeException ("Clone not yet implemented for class " + element.getClass().getName(), e);
+                throw new RuntimeException ("Clone not yet implemented for class " + element.getClass().getName(), e);
             }
             if (! isCopy){
                 description.removeElement(element);
+                if (description.getElements().isEmpty()){
+                   if (description instanceof TaxonDescription){
+                       TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
+                       if (taxDescription.getTaxon() != null){
+                           taxDescription.getTaxon().removeDescription((TaxonDescription)description);
+                       }
+                   }
+                    dao.delete(description);
+                }else{
+                    dao.saveOrUpdate(description);
+                    result.addUpdatedObject(description);
+                }
             }
 
+
+        }
+        dao.saveOrUpdate(targetDescription);
+        result.addUpdatedObject(targetDescription);
+        if (targetDescription instanceof TaxonDescription){
+            result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
         }
+        return result;
     }
 
     @Override
-    public Pager<NamedArea> pageNamedAreasInUse(Integer pageSize,
-            Integer pageNumber, List<String> propertyPaths){
+    @Transactional(readOnly = false)
+    public UpdateResult moveDescriptionElementsToDescription(
+            Set<UUID> descriptionElementUUIDs,
+            UUID targetDescriptionUuid,
+            boolean isCopy) {
+        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
+        for(UUID deUuid : descriptionElementUUIDs) {
+            descriptionElements.add(descriptionElementDao.load(deUuid));
+        }
+        DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
+
+        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
+    }
+
+    @Override
+    @Transactional(readOnly = false)
+    public UpdateResult moveDescriptionElementsToDescription(
+            Set<UUID> descriptionElementUUIDs,
+            UUID targetTaxonUuid,
+            String moveMessage,
+            boolean isCopy) {
+        Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
+        DescriptionBase targetDescription = TaxonDescription.NewInstance(targetTaxon);
+        targetDescription.setTitleCache(moveMessage, true);
+        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
+        annotation.setAnnotationType(AnnotationType.TECHNICAL());
+        targetDescription.addAnnotation(annotation);
+
+        targetDescription = dao.save(targetDescription);
+        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
+        for(UUID deUuid : descriptionElementUUIDs) {
+            descriptionElements.add(descriptionElementDao.load(deUuid));
+        }
 
-        List<NamedArea> results = dao.listNamedAreasInUse(pageSize, pageNumber, propertyPaths);
-        return new DefaultPagerImpl<NamedArea>(pageNumber, results.size(), pageSize, results);
+        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
     }
 
+    @Override
+    public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
+            Integer pageNumber){
+        List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
+        int startIndex= pageNumber * pageSize;
+        int toIndex = Math.min(startIndex + pageSize, results.size());
+        List<TermDto> page = results.subList(startIndex, toIndex);
+        return new DefaultPagerImpl<TermDto>(pageNumber, results.size(), pageSize, page);
+    }
+
+
+    @Override
+    @Transactional(readOnly = false)
+    public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon) {
+        List<TaxonDescription> descriptions = new ArrayList(sourceTaxon.getDescriptions());
+        UpdateResult result = new UpdateResult();
+        result.addUpdatedObject(sourceTaxon);
+        result.addUpdatedObject(targetTaxon);
+        for(TaxonDescription description : descriptions){
+
+            String moveMessage = String.format("Description moved from %s", sourceTaxon);
+            if(description.isProtectedTitleCache()){
+                String separator = "";
+                if(!StringUtils.isBlank(description.getTitleCache())){
+                    separator = " - ";
+                }
+                description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
+            }
+            Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
+            annotation.setAnnotationType(AnnotationType.TECHNICAL());
+            description.addAnnotation(annotation);
+            targetTaxon.addDescription(description);
+        }
+        return result;
+    }
+
+    @Override
+    @Transactional(readOnly = false)
+    public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid) {
+        Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
+        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
+        return moveTaxonDescriptions(sourceTaxon, targetTaxon);
+
+    }
+
+    @Override
+    @Transactional(readOnly = false)
+    public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid){
+        UpdateResult result = new UpdateResult();
+        TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
+
+        Taxon sourceTaxon = description.getTaxon();
+        String moveMessage = String.format("Description moved from %s", sourceTaxon);
+        if(description.isProtectedTitleCache()){
+            String separator = "";
+            if(!StringUtils.isBlank(description.getTitleCache())){
+                separator = " - ";
+            }
+            description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
+        }
+        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
+        annotation.setAnnotationType(AnnotationType.TECHNICAL());
+        description.addAnnotation(annotation);
+        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
+        targetTaxon.addDescription(description);
+        result.addUpdatedObject(targetTaxon);
+        result.addUpdatedObject(sourceTaxon);
+       // dao.merge(description);
+        return result;
+
+    }
 
 }