cleanup
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DescriptionServiceImpl.java
index a741537f2fa8ba9d4b981587c2b867cfcc209e20..b4b003adb28b3adfe0087a5e94871ec2951e8289 100644 (file)
@@ -1,4 +1,3 @@
-// $Id$
 /**
 * Copyright (C) 2007 EDIT
 * European Distributed Institute of Taxonomy
 package eu.etaxonomy.cdm.api.service;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -24,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import eu.etaxonomy.cdm.api.service.dto.TaxonDistributionDTO;
 import eu.etaxonomy.cdm.api.service.pager.Pager;
 import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
@@ -32,6 +34,7 @@ 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,55 +42,66 @@ import eu.etaxonomy.cdm.model.common.MarkerType;
 import eu.etaxonomy.cdm.model.common.TermVocabulary;
 import eu.etaxonomy.cdm.model.description.DescriptionBase;
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
+import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
 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.PresenceAbsenceTerm;
+import eu.etaxonomy.cdm.model.description.SpecimenDescription;
 import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
 import eu.etaxonomy.cdm.model.description.TextData;
 import eu.etaxonomy.cdm.model.location.NamedArea;
 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
 import eu.etaxonomy.cdm.model.media.Media;
-import eu.etaxonomy.cdm.model.name.TaxonNameBase;
+import eu.etaxonomy.cdm.model.name.TaxonName;
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
 import eu.etaxonomy.cdm.model.taxon.Taxon;
 import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
 import eu.etaxonomy.cdm.persistence.dao.common.ITermVocabularyDao;
 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionElementDao;
+import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
 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.dao.taxon.ITaxonNodeDao;
+import eu.etaxonomy.cdm.persistence.dto.MergeResult;
 import eu.etaxonomy.cdm.persistence.dto.TermDto;
 import eu.etaxonomy.cdm.persistence.query.OrderHint;
 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
 
 /**
  * @author a.mueller
- * @created 24.06.2008
- * @version 1.0
- */
-/**
  * @author a.kohlbecker
- * @date Dec 5, 2013
+ *
+ * @since 24.06.2008
  *
  */
 @Service
 @Transactional(readOnly = true)
-public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionBase,IDescriptionDao> implements IDescriptionService {
+public class DescriptionServiceImpl
+        extends IdentifiableServiceBase<DescriptionBase,IDescriptionDao>
+        implements IDescriptionService {
 
     private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
 
     protected IDescriptionElementDao descriptionElementDao;
     protected IFeatureTreeDao featureTreeDao;
+    protected IDescriptiveDataSetDao descriptiveDataSetDao;
     protected IFeatureNodeDao featureNodeDao;
     protected IFeatureDao featureDao;
     protected ITermVocabularyDao vocabularyDao;
     protected IDefinedTermDao definedTermDao;
     protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
     protected ITaxonDao taxonDao;
+    protected ITaxonNodeDao taxonNodeDao;
+    protected IDescriptiveDataSetDao dataSetDao;
+
+    @Autowired
+    private IProgressMonitorService progressMonitorService;
 
     //TODO change to Interface
     private NaturalLanguageGenerator naturalLanguageGenerator;
@@ -97,6 +111,11 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
         this.featureTreeDao = featureTreeDao;
     }
 
+    @Autowired
+    protected void setDescriptiveDataSetDao(IDescriptiveDataSetDao descriptiveDataSetDao) {
+        this.descriptiveDataSetDao = descriptiveDataSetDao;
+    }
+
     @Autowired
     protected void setFeatureNodeDao(IFeatureNodeDao featureNodeDao) {
         this.featureNodeDao = featureNodeDao;
@@ -137,6 +156,16 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
         this.taxonDao = taxonDao;
     }
 
+    @Autowired
+    protected void setTaxonNodeDao(ITaxonNodeDao taxonNodeDao) {
+        this.taxonNodeDao = taxonNodeDao;
+    }
+
+    @Autowired
+    protected void setDataSetDao(IDescriptiveDataSetDao dataSetDao) {
+        this.dataSetDao = dataSetDao;
+    }
+
     /**
      *
      */
@@ -145,10 +174,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) {
@@ -173,65 +198,63 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
     }
 
     @Override
-    public int count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
+    public long count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
         return dao.countDescriptions(type, hasImages, hasText, feature);
     }
 
     @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<>(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(AbstractPagerImpl.hasResultsInRange(numberOfResults.longValue(), pageNumber, pageSize)) {
+        long numberOfResults = dao.countDescriptionElements(description, descriptionType, features, type);
+        List<T> results = new ArrayList<T>();
+        if(AbstractPagerImpl.hasResultsInRange(numberOfResults, 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);
     }
 
     @Override
     public Pager<Annotation> getDescriptionElementAnnotations(DescriptionElementBase annotatedObj, MarkerType status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
-        Integer numberOfResults = descriptionElementDao.countAnnotations(annotatedObj, status);
+        long numberOfResults = descriptionElementDao.countAnnotations(annotatedObj, status);
 
-        List<Annotation> results = new ArrayList<Annotation>();
+        List<Annotation> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
             results = descriptionElementDao.getAnnotations(annotatedObj, status, pageSize, pageNumber, orderHints, propertyPaths);
         }
 
-        return new DefaultPagerImpl<Annotation>(pageNumber, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
     }
 
 
-
     @Override
     public Pager<Media> getMedia(DescriptionElementBase descriptionElement,    Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
         Integer numberOfResults = descriptionElementDao.countMedia(descriptionElement);
@@ -256,20 +279,16 @@ 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);
+        long numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes);
 
-        List<TaxonDescription> results = new ArrayList<TaxonDescription>();
+        List<TaxonDescription> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
             results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
         }
 
-        return new DefaultPagerImpl<TaxonDescription>(pageNumber, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
     }
 
     @Override
@@ -279,33 +298,23 @@ 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){
 
         List<Distribution> distList = new ArrayList<Distribution>();
@@ -351,37 +360,38 @@ 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, hideMarkedAreas, true, statusOrderPreference, false);
+        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distList, hiddenAreaMarkerTypes, true, statusOrderPreference, false);
         distList.clear();
         distList.addAll(filteredDistributions);
 
-        return DescriptionUtility.orderDistributions(definedTermDao, omitLevels, distList);
+        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);
+    public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
+        long numberOfResults = dao.countTaxonNameDescriptions(name);
 
-        List<TaxonNameDescription> results = new ArrayList<TaxonNameDescription>();
+        List<TaxonNameDescription> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
             results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
         }
 
-        return new DefaultPagerImpl<TaxonNameDescription>(pageNumber, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
     }
 
 
     @Override
     public Pager<DescriptionBase> page(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText, Set<Feature> feature, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
-        Integer numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
+        long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
 
-        List<DescriptionBase> results = new ArrayList<DescriptionBase>();
+        @SuppressWarnings("rawtypes")
+        List<DescriptionBase> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
             results = dao.listDescriptions(type, hasImages, hasText, feature, pageSize, pageNumber,orderHints,propertyPaths);
         }
 
-        return new DefaultPagerImpl<DescriptionBase>(pageNumber, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
     }
 
     /**
@@ -390,14 +400,14 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
      */
     @Override
     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);
+        long numberOfResults = dao.countDescriptionByDistribution(namedAreas, presence);
 
-        List<TaxonDescription> results = new ArrayList<TaxonDescription>();
+        List<TaxonDescription> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
             results = dao.searchDescriptionByDistribution(namedAreas, presence, pageSize, pageNumber,orderHints,propertyPaths);
         }
 
-        return new DefaultPagerImpl<TaxonDescription>(pageNumber, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
     }
 
     /**
@@ -405,15 +415,16 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
      * move: descriptionElementService.search
      */
     @Override
-    public Pager<DescriptionElementBase> searchElements(Class<? extends DescriptionElementBase> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
-        Integer numberOfResults = descriptionElementDao.count(clazz, queryString);
+//    public Pager<T> searchElements(Class<? extends T> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+    public <S extends DescriptionElementBase> Pager<S> searchElements(Class<S> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+        long numberOfResults = descriptionElementDao.count(clazz, queryString);
 
-        List<DescriptionElementBase> results = new ArrayList<DescriptionElementBase>();
+        List<S> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
-            results = descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
+            results = (List<S>)descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
         }
 
-        return new DefaultPagerImpl<DescriptionElementBase>(pageNumber, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
     }
 
     /**
@@ -454,6 +465,24 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
         return descriptionElementDao.saveAll(descriptionElements);
     }
 
+    @Override
+    @Transactional(readOnly = false)
+    public List<MergeResult<DescriptionBase>> mergeDescriptionElements(Collection<TaxonDistributionDTO> descriptionElements, boolean returnTransientEntity) {
+        List<MergeResult<DescriptionBase>> mergedObjects = new ArrayList();
+        List<Distribution> toDelete = new ArrayList<>();
+        for(TaxonDistributionDTO obj : descriptionElements) {
+            Iterator<TaxonDescription> iterator = obj.getDescriptionsWrapper().getDescriptions().iterator();
+            while (iterator.hasNext()){
+                TaxonDescription desc = iterator.next();
+                mergedObjects.add(dao.merge(desc, returnTransientEntity));
+            }
+
+
+        }
+
+        return mergedObjects;
+    }
+
     /**
      * FIXME Candidate for harmonization
      * descriptionElementService.delete
@@ -476,16 +505,29 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
     @Transactional(readOnly = false)
     public DeleteResult deleteDescription(DescriptionBase description) {
         DeleteResult deleteResult = new DeleteResult();
+        description = load(description.getId(), Arrays.asList("descriptiveDataSets"));//avoid lazy init exception
 
        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);
        }
+       else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
+           SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(description, SpecimenDescription.class);
+           SpecimenOrObservationBase specimen = specimenDescription.getDescribedSpecimenOrObservation();
+           specimen.removeDescription(specimenDescription);
+           deleteResult.addUpdatedObject(specimen);
+       }
+
+       Set<DescriptiveDataSet> descriptiveDataSets = description.getDescriptiveDataSets();
+       for (Iterator<DescriptiveDataSet> iterator = descriptiveDataSets.iterator(); iterator.hasNext();) {
+           iterator.next().removeDescription(description);
+        }
+
+       dao.delete(description);
+       deleteResult.addDeletedObject(description);
+       deleteResult.setCdmEntity(description);
 
 
         return deleteResult;
@@ -539,7 +581,7 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
             descriptionElements = new ArrayList<T>(0);
         }
         if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
-        return new DefaultPagerImpl<T>(pageNumber, count.intValue(), pageSize, descriptionElements);
+        return new DefaultPagerImpl<T>(pageNumber, count, pageSize, descriptionElements);
     }
 
 
@@ -662,13 +704,15 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
 
 
     @Override
-    public void moveDescriptionElementsToDescription(
+    @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()){
@@ -687,12 +731,67 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
             }
             if (! isCopy){
                 description.removeElement(element);
-                dao.saveOrUpdate(description);
+                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
+    @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));
+        }
+
+        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
     }
 
     @Override
@@ -740,6 +839,32 @@ public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionB
 
     }
 
+    @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;
+
+    }
 
 
 }