Merge branch 'develop' of ssh://dev.e-taxonomy.eu/var/git/cdmlib into develop
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonNodeServiceImpl.java
index f408dc14a9261adeb63704040e83221a94d3adb0..a5e4715f73d9a4eb1b52f6a33142af51eaa74d12 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.UUID;
 
@@ -28,6 +29,7 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
 import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
 import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;
+import eu.etaxonomy.cdm.api.service.config.PublishForSubtreeConfigurator;
 import eu.etaxonomy.cdm.api.service.config.SecundumForSubtreeConfigurator;
 import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
 import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator;
@@ -35,6 +37,7 @@ import eu.etaxonomy.cdm.api.service.dto.CdmEntityIdentifier;
 import eu.etaxonomy.cdm.api.service.dto.TaxonDistributionDTO;
 import eu.etaxonomy.cdm.api.service.pager.Pager;
 import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
+import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
 import eu.etaxonomy.cdm.common.monitor.DefaultProgressMonitor;
 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
@@ -43,8 +46,11 @@ import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
 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.LanguageString;
 import eu.etaxonomy.cdm.model.common.TreeIndex;
+import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
+import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
 import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
@@ -61,11 +67,15 @@ import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
+import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
+import eu.etaxonomy.cdm.model.term.DefinedTerm;
+import eu.etaxonomy.cdm.persistence.dao.common.Restriction;
 import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeFilterDao;
 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
 import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
+import eu.etaxonomy.cdm.persistence.query.OrderHint;
 
 /**
  * @author n.hoffmann
@@ -84,6 +94,9 @@ public class TaxonNodeServiceImpl
     @Autowired
     private ITaxonService taxonService;
 
+    @Autowired
+    private IReferenceService referenceService;
+
     @Autowired
     private IDescriptiveDataSetService dataSetService;
 
@@ -272,7 +285,7 @@ public class TaxonNodeServiceImpl
     @Override
     @Transactional(readOnly = false)
     public DeleteResult makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode,
-            SynonymType synonymType, Reference citation, String citationMicroReference)  {
+            SynonymType synonymType, Reference citation, String citationMicroReference, boolean setNameInSource)  {
 
         // TODO at the moment this method only moves synonym-, concept relations and descriptions to the new accepted taxon
         // in a future version we also want to move cdm data like annotations, marker, so., but we will need a policy for that
@@ -380,13 +393,21 @@ public class TaxonNodeServiceImpl
             taxonRelationship.setFromTaxon(null);
         }
 
-
         //Move descriptions to new taxon
         List<TaxonDescription> descriptions = new ArrayList<TaxonDescription>( oldTaxon.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())
         for(TaxonDescription description : descriptions){
             String message = "Description copied from former accepted taxon: %s (Old title: %s)";
             message = String.format(message, oldTaxon.getTitleCache(), description.getTitleCache());
             description.setTitleCache(message, true);
+            if (setNameInSource) {
+                for (DescriptionElementBase element: description.getElements()){
+                    for (DescriptionElementSource source: element.getSources()){
+                        if (source.getNameUsedInSource() == null){
+                            source.setNameUsedInSource(newSynonymName);
+                        }
+                    }
+                }
+            }
             //oldTaxon.removeDescription(description, false);
             newAcceptedTaxon.addDescription(description);
         }
@@ -426,10 +447,11 @@ public class TaxonNodeServiceImpl
             UUID newAcceptedTaxonNodeUUIDs,
             SynonymType synonymType,
             Reference citation,
-            String citationMicroReference) {
+            String citationMicroReference,
+            boolean setNameInSource) {
        UpdateResult result = new UpdateResult();
        for (UUID nodeUuid: oldTaxonNodeUuids) {
-               result.includeResult(makeTaxonNodeASynonymOfAnotherTaxonNode(nodeUuid, newAcceptedTaxonNodeUUIDs, synonymType, citation, citationMicroReference));
+               result.includeResult(makeTaxonNodeASynonymOfAnotherTaxonNode(nodeUuid, newAcceptedTaxonNodeUUIDs, synonymType, citation, citationMicroReference, setNameInSource));
        }
        return result;
     }
@@ -440,7 +462,8 @@ public class TaxonNodeServiceImpl
             UUID newAcceptedTaxonNodeUUID,
             SynonymType synonymType,
             Reference citation,
-            String citationMicroReference) {
+            String citationMicroReference,
+            boolean setNameInSource) {
 
         TaxonNode oldTaxonNode = dao.load(oldTaxonNodeUuid);
         TaxonNode oldTaxonParentNode = oldTaxonNode.getParent();
@@ -450,7 +473,7 @@ public class TaxonNodeServiceImpl
                 newTaxonNode,
                 synonymType,
                 citation,
-                citationMicroReference);
+                citationMicroReference, setNameInSource);
         result.addUpdatedCdmId(new CdmEntityIdentifier(oldTaxonParentNode.getId(), TaxonNode.class));
         result.addUpdatedCdmId(new CdmEntityIdentifier(newTaxonNode.getId(), TaxonNode.class));
         result.setCdmEntity(oldTaxonParentNode);
@@ -822,7 +845,7 @@ public class TaxonNodeServiceImpl
         TaxonNode parent = dao.load(parentNodeUuid);
         TaxonNode child = null;
         try{
-            child = parent.addChildTaxon(newTaxon, parent.getReference(), parent.getMicroReference());
+            child = parent.addChildTaxon(newTaxon,ref, microref);
         }catch(Exception e){
             result.addException(e);
             result.setError();
@@ -844,21 +867,15 @@ public class TaxonNodeServiceImpl
     public UpdateResult saveNewTaxonNode(TaxonNode newTaxonNode){
         UpdateResult result = new UpdateResult();
         UUID parentUuid = newTaxonNode.getParent().getUuid();
-        TaxonNode parent = dao.load(parentUuid);
-        if (newTaxonNode.getTaxon().getId() != 0){
-            Taxon taxon = (Taxon)taxonService.load(newTaxonNode.getTaxon().getUuid());
-            newTaxonNode.setTaxon(taxon);
-        }else{
-            Taxon taxon = newTaxonNode.getTaxon();
-            taxon.removeTaxonNode(newTaxonNode);
-            UUID taxonUUID = taxonService.saveOrUpdate(taxon);
-            taxon = (Taxon) taxonService.load(taxonUUID);
-            newTaxonNode.setTaxon(taxon);
-        }
+        Taxon taxon = null;
 
-        if (newTaxonNode.getTaxon().getName().getId() != 0){
+        if (newTaxonNode.getTaxon().getId() != 0){
+            taxon = (Taxon)taxonService.load(newTaxonNode.getTaxon().getUuid());
+            //newTaxonNode.setTaxon(taxon);
+        }else if (newTaxonNode.getTaxon().getName().getId() != 0){
             TaxonName name = nameService.load(newTaxonNode.getTaxon().getName().getUuid());
-            newTaxonNode.getTaxon().setName(name);
+            taxon = newTaxonNode.getTaxon();
+            taxon.setName(name);
         }else{
             for (HybridRelationship rel : newTaxonNode.getTaxon().getName().getHybridChildRelations()){
                 if (!rel.getHybridName().isPersited()) {
@@ -869,16 +886,44 @@ public class TaxonNodeServiceImpl
                 }
             }
         }
+        if (taxon == null){
+            taxon = newTaxonNode.getTaxon();
+        }
+        taxon.removeTaxonNode(newTaxonNode);
+
+        if (taxon.getSec() != null && taxon.getSec().isPersited()){
+            Reference sec = referenceService.load(taxon.getSec().getUuid());
+            taxon.setSec(sec);
+        }
+        if (taxon.getId() == 0){
+            UUID taxonUUID = taxonService.saveOrUpdate(taxon);
+            taxon = (Taxon) taxonService.load(taxonUUID);
+
+        }
+
 
+        TaxonNode parent = dao.load(parentUuid);
         TaxonNode child = null;
         try{
-            child = parent.addChildNode(newTaxonNode, newTaxonNode.getReference(), newTaxonNode.getMicroReference());
+            child = parent.addChildTaxon(taxon, newTaxonNode.getReference(), newTaxonNode.getMicroReference());
 
         }catch(Exception e){
             result.addException(e);
             result.setError();
             return result;
         }
+
+        child.setUnplaced(newTaxonNode.isUnplaced());
+        child.setExcluded(newTaxonNode.isExcluded());
+        child.setDoubtful(newTaxonNode.isDoubtful());
+        for (TaxonNodeAgentRelation agentRel :newTaxonNode.getAgentRelations()){
+            child.addAgentRelation(agentRel.getType(), agentRel.getAgent());
+        }
+        for (Entry<Language, LanguageString> entry: newTaxonNode.getExcludedNote().entrySet()){
+            child.putExcludedNote(entry.getKey(), entry.getValue().getText());
+        }
+
+        newTaxonNode = null;
         dao.saveOrUpdate(child);
 
         result.addUpdatedObject(child.getParent());
@@ -987,26 +1032,29 @@ public class TaxonNodeServiceImpl
     }
 
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     @Transactional(readOnly=false)
-    public UpdateResult setPublishForSubtree(UUID subtreeUuid, boolean publish, boolean includeAcceptedTaxa,
-            boolean includeSynonyms, boolean includeSharedTaxa, IProgressMonitor monitor) {
+    public UpdateResult setPublishForSubtree(PublishForSubtreeConfigurator config){
         UpdateResult result = new UpdateResult();
+        IProgressMonitor monitor = config.getMonitor();
         if (monitor == null){
             monitor = DefaultProgressMonitor.NewInstance();
         }
         TreeIndex subTreeIndex = null;
 
-        if (subtreeUuid == null){
+        if (config.getSubtreeUuid() == null){
             result.setError();
             result.addException(new NullPointerException("No subtree given"));
             monitor.done();
             return result;
         }
-        TaxonNode subTree = find(subtreeUuid);
+        TaxonNode subTree = find(config.getSubtreeUuid());
+        boolean includeAcceptedTaxa = config.isIncludeAcceptedTaxa();
+        boolean publish = config.isPublish();
+        boolean includeSynonyms = config.isIncludeSynonyms();
+        boolean includeSharedTaxa = config.isIncludeSharedTaxa();
+        boolean includeHybrids = config.isIncludeHybrids();
+        boolean includeRelatedTaxa = config.isIncludeProParteSynonyms() || config.isIncludeMisapplications();
         if (subTree == null){
             result.setError();
             result.addException(new NullPointerException("Subtree does not exist"));
@@ -1014,28 +1062,41 @@ public class TaxonNodeServiceImpl
             return result;
         }else{
             subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
-            int count = includeAcceptedTaxa ? dao.countPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa):0;
-            count += includeSynonyms ? dao.countPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa):0;
+            int count = includeAcceptedTaxa ? dao.countPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa, includeHybrids):0;
+            count += includeSynonyms ? dao.countPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa, includeHybrids):0;
+            count += includeRelatedTaxa ? dao.countPublishForSubtreeRelatedTaxa(subTreeIndex, publish, includeSharedTaxa, includeHybrids):0;
             monitor.beginTask("Update publish flag", count);
         }
 
 
         if (includeAcceptedTaxa){
             monitor.subTask("Update Accepted Taxa");
-            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa, monitor);
+            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa, includeHybrids, monitor);
             result.addUpdatedObjects(updatedTaxa);
         }
         if (includeSynonyms){
             monitor.subTask("Update Synonyms");
-            Set<TaxonBase> updatedSynonyms = dao.setPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa, monitor);
+            Set<TaxonBase> updatedSynonyms = dao.setPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa, includeHybrids, monitor);
             result.addUpdatedObjects(updatedSynonyms);
         }
+        if (includeRelatedTaxa){
+            monitor.subTask("Update Related Taxa");
+            Set<UUID> relationTypes = new HashSet<>();
+            if (config.isIncludeMisapplications()){
+                relationTypes.addAll(TaxonRelationshipType.misappliedNameUuids());
+            }
+            if (config.isIncludeProParteSynonyms()){
+                relationTypes.addAll(TaxonRelationshipType.proParteOrPartialSynonymUuids());
+            }
+            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeRelatedTaxa(subTreeIndex, publish,
+                    relationTypes, includeSharedTaxa, includeHybrids, monitor);
+            result.addUpdatedObjects(updatedTaxa);
+        }
 
         monitor.done();
         return result;
     }
 
-
     @Override
     public long count(TaxonNodeFilter filter){
         return nodeFilterDao.count(filter);
@@ -1116,6 +1177,26 @@ public class TaxonNodeServiceImpl
         return result;
     }
 
+    @Override
+    public <S extends TaxonNode> Pager<S> page(Class<S> clazz, List<Restriction<?>> restrictions, Integer pageSize,
+            Integer pageIndex, List<OrderHint> orderHints, List<String> propertyPaths) {
+        return page(clazz, restrictions, pageSize, pageIndex, orderHints, propertyPaths, INCLUDE_UNPUBLISHED);
+    }
+
+    @Override
+    public <S extends TaxonNode> Pager<S> page(Class<S> clazz, List<Restriction<?>> restrictions, Integer pageSize,
+            Integer pageIndex, List<OrderHint> orderHints, List<String> propertyPaths, boolean includeUnpublished) {
+
+        List<S> records;
+        long resultSize = dao.count(clazz, restrictions);
+        if(AbstractPagerImpl.hasResultsInRange(resultSize, pageIndex, pageSize)){
+            records = dao.list(clazz, restrictions, pageSize, pageIndex, orderHints, propertyPaths, includeUnpublished);
+        } else {
+            records = new ArrayList<>();
+        }
+        Pager<S> pager = new DefaultPagerImpl<>(pageIndex, resultSize, pageSize, records);
+        return pager;
+    }
 
 
 }