X-Git-Url: https://dev.e-taxonomy.eu/gitweb/cdmlib.git/blobdiff_plain/6b5ba3cc07ffbef015e9cae9f3e7c0fb6cdc78e3..ff722416e765374595e21cc6d7f86d7016130e58:/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ClassificationServiceImpl.java diff --git a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ClassificationServiceImpl.java b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ClassificationServiceImpl.java index 56d135e0a6..7404efea06 100644 --- a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ClassificationServiceImpl.java +++ b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ClassificationServiceImpl.java @@ -14,28 +14,32 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.UUID; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import eu.etaxonomy.cdm.api.service.config.CreateHierarchyForClassificationConfigurator; import eu.etaxonomy.cdm.api.service.pager.Pager; import eu.etaxonomy.cdm.api.service.pager.PagerUtils; import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl; import eu.etaxonomy.cdm.common.monitor.IProgressMonitor; import eu.etaxonomy.cdm.model.common.CdmBase; -import eu.etaxonomy.cdm.model.common.UuidAndTitleCache; import eu.etaxonomy.cdm.model.description.DescriptionElementBase; import eu.etaxonomy.cdm.model.description.TaxonDescription; import eu.etaxonomy.cdm.model.media.Media; import eu.etaxonomy.cdm.model.media.MediaRepresentation; import eu.etaxonomy.cdm.model.media.MediaUtils; +import eu.etaxonomy.cdm.model.name.NonViralName; import eu.etaxonomy.cdm.model.name.Rank; +import eu.etaxonomy.cdm.model.name.TaxonNameBase; import eu.etaxonomy.cdm.model.taxon.Classification; import eu.etaxonomy.cdm.model.taxon.ITaxonNodeComparator; import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode; @@ -45,8 +49,10 @@ import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer; import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao; import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao; import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao; +import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache; import eu.etaxonomy.cdm.persistence.query.OrderHint; import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy; +import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl; /** * @author n.hoffmann @@ -54,7 +60,8 @@ import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy; */ @Service @Transactional(readOnly = true) -public class ClassificationServiceImpl extends IdentifiableServiceBase implements IClassificationService { +public class ClassificationServiceImpl extends IdentifiableServiceBase + implements IClassificationService { private static final Logger logger = Logger.getLogger(ClassificationServiceImpl.class); @Autowired @@ -66,10 +73,6 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase) taxonNodeComparator; } - - /* - * (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IClassificationService#loadTaxonNodeByTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.UUID, java.util.List) - */ @Override public TaxonNode loadTaxonNodeByTaxon(Taxon taxon, UUID classificationUuid, List propertyPaths){ Classification tree = dao.load(classificationUuid); @@ -106,15 +104,11 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase loadRankSpecificRootNodes(Classification classification, Rank rank, Integer limit, Integer start, List propertyPaths){ - List rootNodes = dao.loadRankSpecificRootNodes(classification, rank, limit , start, propertyPaths); + List rootNodes = dao.listRankSpecificRootNodes(classification, rank, limit , start, propertyPaths); //sort nodes by TaxonName Collections.sort(rootNodes, taxonNodeComparator); @@ -125,18 +119,12 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase listRankSpecificRootNodes(Classification classification, Rank rank, Integer pageSize, Integer pageIndex, List propertyPaths) { return pageRankSpecificRootNodes(classification, rank, pageSize, pageIndex, propertyPaths).getRecords(); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IClassificationService#pageRankSpecificRootNodes(eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer, java.util.List) - */ @Override public Pager pageRankSpecificRootNodes(Classification classification, Rank rank, Integer pageSize, Integer pageIndex, List propertyPaths) { @@ -145,7 +133,7 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase results = new ArrayList(); if (numberOfResults > 0) { // no point checking again - results = dao.loadRankSpecificRootNodes(classification, rank, PagerUtils.limitFor(pageSize), + results = dao.listRankSpecificRootNodes(classification, rank, PagerUtils.limitFor(pageSize), PagerUtils.startFor(pageSize, pageIndex), propertyPaths); } @@ -155,7 +143,6 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase loadTreeBranchToTaxon(Taxon taxon, Classification classification, Rank baseRank, List propertyPaths){ Classification tree = dao.load(classification.getUuid()); @@ -216,9 +201,6 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase loadChildNodesOfTaxonNode(TaxonNode taxonNode, List propertyPaths) { @@ -229,38 +211,23 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase loadChildNodesOfTaxon(Taxon taxon, Classification classification, List propertyPaths){ - Classification tree = dao.load(classification.getUuid()); - taxon = (Taxon) taxonDao.load(taxon.getUuid()); - - TaxonNode node = tree.getNode(taxon); - if(node != null){ - return loadChildNodesOfTaxonNode(node, propertyPaths); - } else { - return null; - } - } + public List listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize, + Integer pageIndex, List propertyPaths){ + Classification classification = dao.load(classificationUuid); + Taxon taxon = (Taxon) taxonDao.load(taxonUuid); + List results = dao.listChildrenOf(taxon, classification, pageSize, pageIndex, propertyPaths); + Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao + return results; + } - /* - * (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IClassificationService#getTaxonNodeByUuid(java.util.UUID) - */ @Override public TaxonNode getTaxonNodeByUuid(UUID uuid) { return taxonNodeDao.findByUuid(uuid); } - /* - * (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IClassificationService#getTreeNodeByUuid(java.util.UUID) - */ @Override public ITaxonTreeNode getTreeNodeByUuid(UUID uuid){ ITaxonTreeNode treeNode = taxonNodeDao.findByUuid(uuid); @@ -271,24 +238,15 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase listClassifications(Integer limit, Integer start, List orderHints, List propertyPaths) { return dao.list(limit, start, orderHints, propertyPaths); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IClassificationService#removeTaxonNode(eu.etaxonomy.cdm.model.taxon.Classification) - */ @Override public UUID removeTaxonNode(TaxonNode taxonNode) { return taxonNodeDao.delete(taxonNode); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IClassificationService#removeTreeNode(eu.etaxonomy.cdm.model.taxon.ITreeNode) - */ @Override public UUID removeTreeNode(ITaxonTreeNode treeNode) { if(treeNode instanceof Classification){ @@ -298,33 +256,23 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase saveTaxonNodeAll( Collection taxonNodeCollection) { return taxonNodeDao.saveAll(taxonNodeCollection); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IClassificationService#saveTreeNode(eu.etaxonomy.cdm.model.taxon.ITreeNode) - */ @Override public UUID saveTreeNode(ITaxonTreeNode treeNode) { if(treeNode instanceof Classification){ - return dao.save((Classification) treeNode); + return dao.save((Classification) treeNode).getUuid(); }else if(treeNode instanceof TaxonNode){ - return taxonNodeDao.save((TaxonNode)treeNode); + return taxonNodeDao.save((TaxonNode)treeNode).getUuid(); } return null; } @@ -334,26 +282,16 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification) { return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IdentifiableServiceBase#getUuidAndTitleCache() - */ @Override public List> getUuidAndTitleCache() { return dao.getUuidAndTitleCache(); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IClassificationService#getAllMediaForChildNodes(eu.etaxonomy.cdm.model.taxon.TaxonNode, java.util.List, int, int, int, java.lang.String[]) - */ @Override public Map> getAllMediaForChildNodes( TaxonNode taxonNode, List propertyPaths, int size, @@ -403,9 +341,6 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase clazz, Integer stepSize, IIdentifiableEntityCacheStrategy cacheStrategy, IProgressMonitor monitor) { @@ -415,5 +350,177 @@ public class ClassificationServiceImpl extends IdentifiableServiceBase + */ + + private Map> getSortedGenusList(Collection allNodesOfClassification){ + + if(allNodesOfClassification == null || allNodesOfClassification.isEmpty()){ + return null; + } + Map> sortedGenusMap = new HashMap>(); + for(TaxonNode node:allNodesOfClassification){ + final TaxonNode tn = node; + Taxon taxon = node.getTaxon(); + NonViralName name = CdmBase.deproxy(taxon.getName(), NonViralName.class); + String genusOrUninomial = name.getGenusOrUninomial(); + //if rank unknown split string and take first word + if(genusOrUninomial == null){ + String titleCache = taxon.getTitleCache(); + String[] split = titleCache.split("\\s+"); + for(String s:split){ + genusOrUninomial = s; + break; + } + } + //if node has children + + //retrieve list from map if not create List + if(sortedGenusMap.containsKey(genusOrUninomial)){ + List list = sortedGenusMap.get(genusOrUninomial); + list.add(node); + sortedGenusMap.put(genusOrUninomial, list); + }else{ + //create List for genus + List list = new ArrayList(); + list.add(node); + sortedGenusMap.put(genusOrUninomial, list); + } + } + return sortedGenusMap; + } + + /** + * + * creates new Classification and parent TaxonNodes at genus level + * + * + * @param map GenusMap which holds a name (Genus) and all the same Taxa as a list + * @param classification you want to improve the hierarchy (will not be modified) + * @param configurator to change certain settings, if null then standard settings will be taken + * @return new classification with parentNodes for each entry in the map + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Transactional(readOnly = false) + @Override + public UpdateResult createHierarchyInClassification(Classification classification, CreateHierarchyForClassificationConfigurator configurator){ + UpdateResult result = new UpdateResult(); + classification = dao.findByUuid(classification.getUuid()); + Map> map = getSortedGenusList(classification.getAllNodes()); + + final String APPENDIX = "repaired"; + String titleCache = org.apache.commons.lang.StringUtils.isBlank(classification.getTitleCache()) ? " " : classification.getTitleCache() ; + //TODO classification clone??? + Classification newClassification = Classification.NewInstance(titleCache +" "+ APPENDIX); + newClassification.setReference(classification.getReference()); + + for(Map.Entry> entry:map.entrySet()){ + String genus = entry.getKey(); + List listOfTaxonNodes = entry.getValue(); + TaxonNode parentNode = null; + //Search for genus in list + for(TaxonNode tNode:listOfTaxonNodes){ + //take that taxonNode as parent and remove from list with all it possible children + //FIXME NPE for name + TaxonNameBase name = tNode.getTaxon().getName(); + NonViralName nonViralName = CdmBase.deproxy(name, NonViralName.class); + if(nonViralName.getNameCache().equalsIgnoreCase(genus)){ + TaxonNode clone = (TaxonNode) tNode.clone(); + if(!tNode.hasChildNodes()){ + //FIXME remove classification +// parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference()); + parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference()); + //remove taxonNode from list because just added to classification + result.addUpdatedObject(tNode); + listOfTaxonNodes.remove(tNode); + }else{ + //get all childNodes + //save prior Hierarchy and remove them from the list + List copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tNode, clone, result); +// parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference()); + //FIXME remove classification + parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference()); + //remove taxonNode from list because just added to classification + result.addUpdatedObject(tNode); + listOfTaxonNodes.remove(tNode); + if(copyAllChildrenToTaxonNode != null){ + listOfTaxonNodes = (List) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode); + } + } + break; + } + } + if(parentNode == null){ + //if no match found in list, create parentNode + NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance(); + NonViralName nonViralName = parser.parseFullName(genus); + TaxonNameBase taxonNameBase = nonViralName; + //TODO Sec via configurator + Taxon taxon = Taxon.NewInstance(taxonNameBase, null); + parentNode = newClassification.addChildTaxon(taxon, 0, null, null); + result.addUpdatedObject(parentNode); + } + //iterate over the rest of the list + for(TaxonNode tn : listOfTaxonNodes){ + //if TaxonNode has a parent and this is not the classification then skip it + //and add to new classification via the parentNode as children of it + //this should assures to keep the already existing hierarchy + //FIXME: Assert is not rootnode --> entrypoint is not classification in future but rather rootNode + + if(!tn.isTopmostNode()){ + continue; //skip to next taxonNode + } + + TaxonNode clone = (TaxonNode) tn.clone(); + //FIXME: citation from node + //TODO: addchildNode without citation and references +// TaxonNode taxonNode = parentNode.addChildNode(clone, classification.getCitation(), classification.getMicroReference()); + TaxonNode taxonNode = parentNode.addChildNode(clone, clone.getReference(), clone.getMicroReference()); + result.addUnChangedObject(clone); + if(tn.hasChildNodes()){ + //save hierarchy in new classification + List copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tn, taxonNode, result); + if(copyAllChildrenToTaxonNode != null){ + listOfTaxonNodes = (List) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode); + } + } + } + } + dao.saveOrUpdate(newClassification); + result.setCdmEntity(newClassification); + return result; + } + + /** + * + * recursive method to get all childnodes of taxonNode in classification. + * + * @param classification just for References and Citation, can be null + * @param copyFromNode TaxonNode with Children + * @param copyToNode TaxonNode which will receive the children + * @return List of ChildNode which has been added. If node has no children returns null + */ + private List copyAllChildrenToTaxonNode(TaxonNode copyFromNode, TaxonNode copyToNode, UpdateResult result) { + List childNodes; + if(!copyFromNode.hasChildNodes()){ + return null; + }else{ + childNodes = copyFromNode.getChildNodes(); + } + for(TaxonNode childNode:childNodes){ + TaxonNode clone = (TaxonNode) childNode.clone(); + result.addUnChangedObject(clone); + if(childNode.hasChildNodes()){ + copyAllChildrenToTaxonNode(childNode, clone, result); + } + //FIXME: citation from node instead of classification +// copyToNode.addChildNode(clone,classification.getCitation(), classification.getMicroReference()); + copyToNode.addChildNode(clone, clone.getReference(), clone.getMicroReference()); + } + return childNodes; + } }