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;
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
*/
@Service
@Transactional(readOnly = true)
-public class ClassificationServiceImpl extends IdentifiableServiceBase<Classification, IClassificationDao> implements IClassificationService {
+public class ClassificationServiceImpl extends IdentifiableServiceBase<Classification, IClassificationDao>
+ implements IClassificationService {
private static final Logger logger = Logger.getLogger(ClassificationServiceImpl.class);
@Autowired
@Autowired
private IBeanInitializer defaultBeanInitializer;
-
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.ServiceBase#setDao(eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao)
- */
@Override
@Autowired
protected void setDao(IClassificationDao dao) {
this.taxonNodeComparator = (Comparator<? super TaxonNode>) 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<String> propertyPaths){
Classification tree = dao.load(classificationUuid);
return taxonNodeDao.load(taxonNodeUuid, propertyPaths);
}
- /*
- * (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.IClassificationService#loadRankSpecificRootNodes(eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.model.name.Rank, java.util.List)
- */
@Override
@Deprecated
public List<TaxonNode> loadRankSpecificRootNodes(Classification classification, Rank rank, Integer limit, Integer start, List<String> propertyPaths){
- List<TaxonNode> rootNodes = dao.loadRankSpecificRootNodes(classification, rank, limit , start, propertyPaths);
+ List<TaxonNode> rootNodes = dao.listRankSpecificRootNodes(classification, rank, limit , start, propertyPaths);
//sort nodes by TaxonName
Collections.sort(rootNodes, taxonNodeComparator);
return rootNodes;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.IClassificationService#listRankSpecificRootNodes(eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer, java.util.List)
- */
@Override
public List<TaxonNode> listRankSpecificRootNodes(Classification classification, Rank rank, Integer pageSize,
Integer pageIndex, List<String> 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<TaxonNode> pageRankSpecificRootNodes(Classification classification, Rank rank, Integer pageSize,
Integer pageIndex, List<String> propertyPaths) {
List<TaxonNode> results = new ArrayList<TaxonNode>();
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);
}
}
/**
- * (non-Javadoc)
* @implements {@link IClassificationService#loadTreeBranch(TaxonNode, Rank, List)
* @see eu.etaxonomy.cdm.api.service.ITaxonService#loadTreeBranchTo(eu.etaxonomy.cdm.model.taxon.TaxonNode, eu.etaxonomy.cdm.model.name.Rank, java.util.List)
* FIXME Candidate for harmonization
while(!thisNode.isTopmostNode()){
//TODO why do we need to deproxy here?
+ // without this thisNode.getParent() will return NULL in
+ // some cases (environment dependend?) even if the parent exits
TaxonNode parentNode = CdmBase.deproxy(thisNode, TaxonNode.class).getParent();
if(parentNode == null){
throw new NullPointerException("The name of the taxon associated with taxonNode " + parentNode + " is NULL");
}
- Rank parentNodeRank = parentNode.getTaxon().getName().getRank();
+ Rank parentNodeRank = parentNode.getTaxon().getName() == null ? null : parentNode.getTaxon().getName().getRank();
// stop if the next parent is higher than the baseRank
- if(baseRank != null && baseRank.isLower(parentNodeRank)){
+ if(baseRank != null && parentNodeRank != null && baseRank.isLower(parentNodeRank)){
break;
}
return pathToRoot;
}
- /*
- * (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.IClassificationService#loadTreeBranchToTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.model.name.Rank, java.util.List)
- */
@Override
public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification, Rank baseRank, List<String> propertyPaths){
Classification tree = dao.load(classification.getUuid());
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.IClassificationService#loadChildNodesOfTaxon(eu.etaxonomy.cdm.model.taxon.TaxonNode, java.util.List)
- */
@Override
public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
List<String> propertyPaths) {
return childNodes;
}
- /*
- * (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.IClassificationService#loadChildNodesOfTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List)
- */
@Override
- public List<TaxonNode> loadChildNodesOfTaxon(Taxon taxon, Classification classification, List<String> 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<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
+ Integer pageIndex, List<String> propertyPaths){
+ Classification classification = dao.load(classificationUuid);
+ Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
+ List<TaxonNode> 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);
return treeNode;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.IClassificationService#listClassifications(java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
- */
@Override
public List<Classification> listClassifications(Integer limit, Integer start, List<OrderHint> orderHints, List<String> 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){
}
return null;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.IClassificationService#saveTaxonNode(eu.etaxonomy.cdm.model.taxon.Classification)
- */
@Override
public UUID saveTaxonNode(TaxonNode taxonNode) {
- return taxonNodeDao.save(taxonNode);
+ return taxonNodeDao.save(taxonNode).getUuid();
}
- /*
- * (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.IClassificationService#saveTaxonNodeAll(java.util.Collection)
- */
@Override
public Map<UUID, TaxonNode> saveTaxonNodeAll(
Collection<TaxonNode> 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;
}
return taxonNodeDao.list(null,null);
}
- /*
- * (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheOfAcceptedTaxa(eu.etaxonomy.cdm.model.taxon.Classification)
- */
@Override
public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification) {
return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification);
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.IdentifiableServiceBase#getUuidAndTitleCache()
- */
@Override
public List<UuidAndTitleCache<Classification>> 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<UUID, List<MediaRepresentation>> getAllMediaForChildNodes(
TaxonNode taxonNode, List<String> propertyPaths, int size,
return getAllMediaForChildNodes(node, propertyPaths, size, height, widthOrDuration, mimeTypes);
}
- /* (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 Classification> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<Classification> cacheStrategy, IProgressMonitor monitor) {
super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
}
+ /**
+ *
+ * @param allNodesOfClassification
+ * @return null - if allNodesOfClassification is empty <br>
+ */
+
+ private Map<String, List<TaxonNode>> getSortedGenusList(Collection<TaxonNode> allNodesOfClassification){
+
+ if(allNodesOfClassification == null || allNodesOfClassification.isEmpty()){
+ return null;
+ }
+ Map<String, List<TaxonNode>> sortedGenusMap = new HashMap<String, List<TaxonNode>>();
+ 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<TaxonNode> list = sortedGenusMap.get(genusOrUninomial);
+ list.add(node);
+ sortedGenusMap.put(genusOrUninomial, list);
+ }else{
+ //create List for genus
+ List<TaxonNode> list = new ArrayList<TaxonNode>();
+ 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<String, List<TaxonNode>> 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<String, List<TaxonNode>> entry:map.entrySet()){
+ String genus = entry.getKey();
+ List<TaxonNode> 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<TaxonNode> 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<TaxonNode>) 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<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tn, taxonNode, result);
+ if(copyAllChildrenToTaxonNode != null){
+ listOfTaxonNodes = (List<TaxonNode>) 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<TaxonNode> copyAllChildrenToTaxonNode(TaxonNode copyFromNode, TaxonNode copyToNode, UpdateResult result) {
+ List<TaxonNode> 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;
+ }
}