-// $Id$\r
/**\r
* Copyright (C) 2007 EDIT\r
* European Distributed Institute of Taxonomy\r
package eu.etaxonomy.cdm.persistence.dao.hibernate.taxon;\r
\r
import java.math.BigInteger;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Iterator;\r
import java.util.List;\r
+import java.util.Map;\r
import java.util.Set;\r
import java.util.UUID;\r
\r
import org.apache.log4j.Logger;\r
import org.hibernate.Criteria;\r
+import org.hibernate.Hibernate;\r
import org.hibernate.Query;\r
+import org.hibernate.criterion.ProjectionList;\r
import org.hibernate.criterion.Projections;\r
import org.hibernate.criterion.Restrictions;\r
import org.springframework.beans.factory.annotation.Autowired;\r
import org.springframework.beans.factory.annotation.Qualifier;\r
import org.springframework.stereotype.Repository;\r
\r
+import eu.etaxonomy.cdm.common.CdmUtils;\r
+import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;\r
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
+import eu.etaxonomy.cdm.model.common.CdmBase;\r
+import eu.etaxonomy.cdm.model.common.TreeIndex;\r
+import eu.etaxonomy.cdm.model.name.Rank;\r
+import eu.etaxonomy.cdm.model.name.TaxonName;\r
+import eu.etaxonomy.cdm.model.reference.Reference;\r
import eu.etaxonomy.cdm.model.taxon.Classification;\r
import eu.etaxonomy.cdm.model.taxon.Taxon;\r
+import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;\r
+import eu.etaxonomy.cdm.model.taxon.UuidAndTitleCacheTaxonComparator;\r
+import eu.etaxonomy.cdm.persistence.dao.common.Restriction;\r
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.AnnotatableDaoImpl;\r
import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;\r
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;\r
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;\r
+import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;\r
+import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;\r
+import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
\r
/**\r
* @author a.mueller\r
- * @created 16.06.2009\r
+ * @since 16.06.2009\r
*/\r
@Repository\r
@Qualifier("taxonNodeDaoHibernateImpl")\r
@Override\r
public UUID delete(TaxonNode persistentObject, boolean deleteChildren){\r
Taxon taxon = persistentObject.getTaxon();\r
- taxon = HibernateProxyHelper.deproxy(taxon, Taxon.class);\r
+ taxon = HibernateProxyHelper.deproxy(taxon);\r
\r
/*Session session = this.getSession();\r
Query query = session.createQuery("from TaxonNode t where t.taxon = :taxon");\r
query.setParameter("taxon", taxon);\r
List result = query.list();*/\r
if (taxon != null){\r
+ Hibernate.initialize(taxon);\r
+ Hibernate.initialize(taxon.getTaxonNodes());\r
Set<TaxonNode> nodes = taxon.getTaxonNodes();\r
-\r
- if (nodes.size()==1){\r
-\r
- TaxonNode node = nodes.iterator().next();\r
- node = HibernateProxyHelper.deproxy(node, TaxonNode.class);\r
-\r
- taxon.removeTaxonNode(node, deleteChildren);\r
- taxonDao.delete(taxon);\r
+ //Hibernate.initialize(taxon.getTaxonNodes());\r
+ for (TaxonNode node:nodes) {\r
+ node = HibernateProxyHelper.deproxy(node);\r
+\r
+ if (node.equals(persistentObject)){\r
+ if (node.hasChildNodes()){\r
+ Iterator<TaxonNode> childNodes = node.getChildNodes().iterator();\r
+ TaxonNode childNode;\r
+ List<TaxonNode> listForDeletion = new ArrayList<>();\r
+ while (childNodes.hasNext()){\r
+ childNode = childNodes.next();\r
+ listForDeletion.add(childNode);\r
+ childNodes.remove();\r
+\r
+ }\r
+ for (TaxonNode deleteNode:listForDeletion){\r
+ delete(deleteNode, deleteChildren);\r
+ }\r
+ }\r
+\r
+ taxon.removeTaxonNode(node, deleteChildren);\r
+ taxonDao.saveOrUpdate(taxon);\r
+ taxon = HibernateProxyHelper.deproxy(taxonDao.findByUuid(taxon.getUuid()), Taxon.class);\r
+ taxonDao.delete(taxon);\r
+\r
+ }\r
}\r
}\r
- //persistentObject.delete();\r
-\r
- super.delete(persistentObject);\r
\r
+ UUID result = super.delete(persistentObject);\r
\r
-\r
- //taxon = (Taxon)taxonDao.findByUuid(taxon.getUuid());\r
- return persistentObject.getUuid();\r
+ return result;\r
}\r
\r
@Override\r
limit = "LIMIT "+start+"," +end;\r
}\r
//FIXME write test\r
- String queryString = "SELECT DISTINCT nodes.*,taxa.titleCache FROM TaxonNode AS nodes LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id WHERE taxa.DTYPE = 'Taxon' AND nodes.classification_id = " + classificationId + " ORDER BY taxa.titleCache " + limit;\r
+ String queryString = "SELECT DISTINCT nodes.*,taxa.titleCache "\r
+ + " FROM TaxonNode AS nodes "\r
+ + " LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id "\r
+ + " WHERE taxa.DTYPE = 'Taxon' "\r
+ + " AND nodes.classification_id = " + classificationId +\r
+ " ORDER BY taxa.titleCache " + limit;\r
+ @SuppressWarnings("unchecked")\r
List<TaxonNode> result = getSession().createSQLQuery(queryString).addEntity(TaxonNode.class).list();\r
\r
return result;\r
-\r
-\r
}\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao#countTaxonOfAcceptedTaxaByClassification(eu.etaxonomy.cdm.model.taxon.Classification)\r
- */\r
+\r
@Override\r
public int countTaxonOfAcceptedTaxaByClassification(Classification classification){\r
int classificationId = classification.getId();\r
//FIXME write test\r
- String queryString = "SELECT DISTINCT COUNT('nodes.*') FROM TaxonNode AS nodes LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id WHERE taxa.DTYPE = 'Taxon' AND nodes.classification_id = " + classificationId;\r
- List<BigInteger> result = getSession().createSQLQuery(queryString).list();\r
+ String queryString = ""\r
+ + " SELECT DISTINCT COUNT('nodes.*') "\r
+ + " FROM TaxonNode AS nodes "\r
+ + " LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id "\r
+ + " WHERE taxa.DTYPE = 'Taxon' AND nodes.classification_id = " + classificationId;\r
+ @SuppressWarnings("unchecked")\r
+ List<BigInteger> result = getSession().createSQLQuery(queryString).list();\r
return result.get(0).intValue ();\r
}\r
\r
@Override\r
- public List<TaxonNode> listChildrenOf(TaxonNode node, Integer pageSize, Integer pageIndex, List<String> propertyPaths, boolean recursive){\r
- if (recursive == true){\r
- Criteria crit = getSession().createCriteria(TaxonNode.class);\r
- crit.add( Restrictions.like("treeIndex", node.treeIndex()+ "%") );\r
+ public List<UuidAndTitleCache<TaxonNode>> listChildNodesAsUuidAndTitleCache(UuidAndTitleCache<TaxonNode> parent) {\r
+ String queryString =\r
+ " SELECT tn.uuid, tn.id, t.titleCache "\r
+ + " FROM TaxonNode tn "\r
+ + " INNER JOIN tn.taxon AS t "\r
+ + " WHERE tn.parent.uuid = :parentId";\r
+\r
+ Query query = getSession().createQuery(queryString);\r
+ query.setParameter("parentId", parent.getUuid());\r
+\r
+ @SuppressWarnings("unchecked")\r
+ List<Object[]> result = query.list();\r
+\r
+ List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>();\r
+ for(Object[] object : result){\r
+ list.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));\r
+ }\r
+ return list;\r
+ }\r
+\r
+ @Override\r
+ public List<TaxonNodeDto> listChildNodesAsTaxonNodeDto(UuidAndTitleCache<TaxonNode> parent) {\r
+ String queryString =\r
+ " SELECT tn "\r
+ + " FROM TaxonNode tn "\r
+ + " INNER JOIN tn.taxon AS t "\r
+ + " WHERE tn.parent.uuid = :parentId";\r
+ Query query = getSession().createQuery(queryString);\r
+ query.setParameter("parentId", parent.getUuid());\r
+\r
+ @SuppressWarnings("unchecked")\r
+ List<TaxonNode> result = query.list();\r
+\r
+ List<TaxonNodeDto> list = new ArrayList<>();\r
+ for(TaxonNode object : result){\r
+ list.add(new TaxonNodeDto(object));\r
+ }\r
+ return list;\r
+ }\r
+\r
+ @Override\r
+ public List<UuidAndTitleCache<TaxonNode>> getUuidAndTitleCache(Integer limit, String pattern, UUID classificationUuid) {\r
+ String queryString = "SELECT tn.uuid, tn.id, t.titleCache, t.name.rank "\r
+ + " FROM TaxonNode tn "\r
+ + " INNER JOIN tn.taxon AS t "\r
+ + " INNER JOIN tn.classification AS cls "\r
+ + "WHERE t.titleCache LIKE :pattern ";\r
+ if(classificationUuid != null){\r
+ queryString += "AND cls.uuid = :classificationUuid";\r
+ }\r
+ Query query = getSession().createQuery(queryString);\r
+\r
+ query.setParameter("pattern", pattern.toLowerCase()+"%");\r
+ query.setParameter("classificationUuid", classificationUuid);\r
+\r
+\r
+ @SuppressWarnings("unchecked")\r
+ List<Object[]> result = query.list();\r
+ Collections.sort(result, new UuidAndTitleCacheTaxonComparator());\r
+\r
+ List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>();\r
+ for(Object[] object : result){\r
+ list.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));\r
+ }\r
+ return list;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public UuidAndTitleCache<TaxonNode> getParentUuidAndTitleCache(UuidAndTitleCache<TaxonNode> child) {\r
+ String queryString = ""\r
+ + " SELECT tn.parent.uuid, tn.parent.id, tn.parent.taxon.titleCache, "\r
+ + " tn.parent.classification.titleCache "\r
+ + " FROM TaxonNode tn"\r
+ + " LEFT OUTER JOIN tn.parent.taxon"\r
+ + " WHERE tn.id = :childId";\r
+ Query query = getSession().createQuery(queryString);\r
+ query.setParameter("childId", child.getId());\r
+ List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>();\r
+\r
+ @SuppressWarnings("unchecked")\r
+ List<Object[]> result = query.list();\r
+\r
+ for(Object[] object : result){\r
+ UUID uuid = (UUID) object[0];\r
+ Integer id = (Integer) object[1];\r
+ String taxonTitleCache = (String) object[2];\r
+ String classificationTitleCache = (String) object[3];\r
+ if(taxonTitleCache!=null){\r
+ list.add(new UuidAndTitleCache<>(uuid,id, taxonTitleCache));\r
+ }\r
+ else{\r
+ list.add(new UuidAndTitleCache<>(uuid,id, classificationTitleCache));\r
+ }\r
+ }\r
+ if(list.size()==1){\r
+ return list.iterator().next();\r
+ }\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public List<TaxonNode> listChildrenOf(TaxonNode node, Integer pageSize, Integer pageIndex,\r
+ boolean recursive, boolean includeUnpublished, List<String> propertyPaths){\r
+\r
+ if (recursive == true){\r
+ Criteria crit = childrenOfCriteria(node, includeUnpublished);\r
+\r
if(pageSize != null) {\r
crit.setMaxResults(pageSize);\r
if(pageIndex != null) {\r
crit.setFirstResult(0);\r
}\r
}\r
- List<TaxonNode> results = crit.list();\r
+ @SuppressWarnings("unchecked")\r
+ List<TaxonNode> results = crit.list();\r
results.remove(node);\r
defaultBeanInitializer.initializeAll(results, propertyPaths);\r
return results;\r
}else{\r
- return classificationDao.listChildrenOf(node.getTaxon(), node.getClassification(), pageSize, pageIndex, propertyPaths);\r
+ return classificationDao.listChildrenOf(node.getTaxon(), node.getClassification(), null,\r
+ includeUnpublished, pageSize, pageIndex, propertyPaths);\r
}\r
\r
}\r
\r
@Override\r
public Long countChildrenOf(TaxonNode node, Classification classification,\r
- boolean recursive) {\r
+ boolean recursive, boolean includeUnpublished) {\r
\r
if (recursive == true){\r
- Criteria crit = getSession().createCriteria(TaxonNode.class);\r
- crit.add( Restrictions.like("treeIndex", node.treeIndex()+ "%") );\r
+ Criteria crit = childrenOfCriteria(node, includeUnpublished);\r
crit.setProjection(Projections.rowCount());\r
return ((Integer)crit.uniqueResult().hashCode()).longValue();\r
}else{\r
- return classificationDao.countChildrenOf(node.getTaxon(), classification);\r
+ return classificationDao.countChildrenOf(\r
+ node.getTaxon(), classification, null, includeUnpublished);\r
}\r
}\r
+ /**\r
+ * @param node\r
+ * @param includeUnpublished\r
+ * @return\r
+ */\r
+ private Criteria childrenOfCriteria(TaxonNode node, boolean includeUnpublished) {\r
+ Criteria crit = getSession().createCriteria(TaxonNode.class);\r
+ crit.add( Restrictions.like("treeIndex", node.treeIndex()+ "%") );\r
+ if (!includeUnpublished){\r
+ crit.createCriteria("taxon").add( Restrictions.eq("publish", Boolean.TRUE));\r
+ }\r
+ return crit;\r
+ }\r
/**\r
* {@inheritDoc}\r
*/\r
@Override\r
public List<TaxonNodeAgentRelation> listTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,\r
- Integer start, Integer limit, List<String> propertyPaths) {\r
-\r
- String hql = "select tnar from TaxonNodeAgentRelation as tnar "\r
- + "join tnar.taxonNode as tn "\r
- + "join tn.taxon as t "\r
- + "join tn.classification as c "\r
- + "join fetch tnar.agent as a "\r
- + "where t.uuid = :taxonUuid and c.uuid = :classificationUuid "\r
- + "order by a.titleCache";\r
- Query query = getSession().createQuery(hql);\r
+ UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer start, Integer limit,\r
+ List<String> propertyPaths) {\r
+\r
+ StringBuilder hql = prepareListTaxonNodeAgentRelations(taxonUuid, classificationUuid,\r
+ agentUuid, rankUuid, relTypeUuid, false);\r
+\r
+ Query query = getSession().createQuery(hql.toString());\r
\r
if(limit != null) {\r
query.setMaxResults(limit);\r
}\r
}\r
\r
- query.setParameter("taxonUuid", taxonUuid);\r
- query.setParameter("classificationUuid", classificationUuid);\r
+ setParamsForListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, query);\r
\r
+ @SuppressWarnings("unchecked")\r
List<TaxonNodeAgentRelation> records = query.list();\r
\r
if(propertyPaths != null) {\r
}\r
return records;\r
}\r
+\r
+ @Override\r
+ public <S extends TaxonNode> List<S> list(Class<S> type, List<Restriction<?>> restrictions, Integer limit,\r
+ Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+ // TODO Auto-generated method stub\r
+ return list(type, restrictions, limit, start, orderHints, propertyPaths, INCLUDE_UNPUBLISHED);\r
+ }\r
+\r
+ @Override\r
+ public <S extends TaxonNode> List<S> list(Class<S> type, List<Restriction<?>> restrictions, Integer limit,\r
+ Integer start, List<OrderHint> orderHints, List<String> propertyPaths, boolean includePublished) {\r
+\r
+ Criteria criteria = createCriteria(type, restrictions, false);\r
+\r
+ if(!includePublished){\r
+ criteria.add(Restrictions.eq("taxon.publish", true));\r
+ }\r
+\r
+ addLimitAndStart(criteria, limit, start);\r
+ addOrder(criteria, orderHints);\r
+\r
+ @SuppressWarnings("unchecked")\r
+ List<S> result = criteria.list();\r
+ defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+ return result;\r
+ }\r
+\r
+\r
+ @Override\r
+ public long count(Class<? extends TaxonNode> type, List<Restriction<?>> restrictions) {\r
+ return count(type, restrictions, INCLUDE_UNPUBLISHED);\r
+ }\r
+\r
+\r
+ @Override\r
+ public long count(Class<? extends TaxonNode> type, List<Restriction<?>> restrictions, boolean includePublished) {\r
+\r
+ Criteria criteria = createCriteria(type, restrictions, false);\r
+ if(!includePublished){\r
+ criteria.add(Restrictions.eq("taxon.publish", true));\r
+ }\r
+ criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));\r
+ return (Long) criteria.uniqueResult();\r
+ }\r
+\r
+\r
/**\r
* {@inheritDoc}\r
*/\r
@Override\r
- public long countTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid) {\r
- String hql = "select count(tnar) from TaxonNodeAgentRelation as tnar "\r
- + "join tnar.taxonNode as tn "\r
- + "join tn.taxon as t "\r
- + "join tn.classification as c "\r
- + "where t.uuid = :taxonUuid and c.uuid = :classificationUuid";\r
- Query query = getSession().createQuery(hql);\r
+ public long countTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid, UUID rankUuid, UUID relTypeUuid) {\r
\r
- query.setParameter("taxonUuid", taxonUuid);\r
- query.setParameter("classificationUuid", classificationUuid);\r
+ StringBuilder hql = prepareListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, true);\r
+ Query query = getSession().createQuery(hql.toString());\r
+\r
+ setParamsForListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, query);\r
\r
Long count = Long.parseLong(query.uniqueResult().toString());\r
\r
return count;\r
}\r
+ /**\r
+ * @param taxonUuid\r
+ * @param classificationUuid\r
+ * @param agentUuid\r
+ * @param relTypeUuid TODO\r
+ * @param doCount TODO\r
+ * @param rankId\r
+ * limit to taxa having this rank, only applies if <code>taxonUuid = null</code>\r
+ * @return\r
+ */\r
+ private StringBuilder prepareListTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid, UUID rankUuid, UUID relTypeUuid, boolean doCount) {\r
+\r
+ StringBuilder hql = new StringBuilder();\r
+\r
+ String join_fetch_mode = doCount ? "JOIN" : "JOIN FETCH";\r
+\r
+ if(doCount) {\r
+ hql.append("SELECT COUNT(tnar)");\r
+ } else {\r
+ hql.append("SELECT tnar");\r
+ }\r
+\r
+ hql.append(" FROM TaxonNodeAgentRelation AS tnar ");\r
+ if(taxonUuid != null) {\r
+ // taxonUuid is search filter, do not fetch it\r
+ hql.append(" JOIN tnar.taxonNode AS tn "\r
+ + " JOIN tn.taxon AS t ");\r
+ } else {\r
+ hql.append(join_fetch_mode)\r
+ .append(" tnar.taxonNode AS tn ")\r
+ .append(join_fetch_mode).append(" tn.taxon AS t ");\r
+ if(rankUuid != null) {\r
+ hql.append(" join t.name as n ");\r
+ }\r
+ }\r
+ hql.append(" JOIN tn.classification AS c ");\r
+ if(agentUuid != null) {\r
+ // agentUuid is search filter, do not fetch it\r
+// hql.append(" join tnar.agent as a ");\r
+ hql.append(join_fetch_mode).append(" tnar.agent AS a ");\r
+ } else {\r
+ hql.append(join_fetch_mode).append(" tnar.agent AS a ");\r
+ }\r
+\r
+ hql.append(" WHERE (1 = 1) ");\r
+\r
+ if(relTypeUuid != null) {\r
+ hql.append(" AND tnar.type.uuid = :relTypeUuid ");\r
+ }\r
+\r
+ if(taxonUuid != null) {\r
+ hql.append(" AND t.uuid = :taxonUuid ");\r
+ } else {\r
+ if(rankUuid != null) {\r
+ hql.append(" AND n.rank.uuid = :rankUuid ");\r
+ }\r
+ }\r
+ if(classificationUuid != null) {\r
+ hql.append(" AND c.uuid = :classificationUuid ");\r
+ }\r
+ if(agentUuid != null) {\r
+ hql.append(" AND a.uuid = :agentUuid ");\r
+ }\r
+\r
+ hql.append(" ORDER BY a.titleCache");\r
+ return hql;\r
+ }\r
+ /**\r
+ * @param taxonUuid\r
+ * @param classificationUuid\r
+ * @param agentUuid\r
+ * @param relTypeUuid TODO\r
+ * @param query\r
+ * @param rankId TODO\r
+ */\r
+ private void setParamsForListTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid,\r
+ UUID rankUuid, UUID relTypeUuid, Query query) {\r
+\r
+ if(taxonUuid != null) {\r
+ query.setParameter("taxonUuid", taxonUuid);\r
+ } else {\r
+ if(rankUuid != null) {\r
+ query.setParameter("rankUuid", rankUuid);\r
+ }\r
+ }\r
+ if(classificationUuid != null) {\r
+ query.setParameter("classificationUuid", classificationUuid);\r
+ }\r
+ if(agentUuid != null) {\r
+ query.setParameter("agentUuid", agentUuid);\r
+ }\r
+ if(relTypeUuid != null) {\r
+ query.setParameter("relTypeUuid", relTypeUuid);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public Map<TreeIndex, Integer> rankOrderIndexForTreeIndex(List<TreeIndex> treeIndexes,\r
+ Integer minRankOrderIndex,\r
+ Integer maxRankOrderIndex) {\r
+\r
+ Map<TreeIndex, Integer> result = new HashMap<>();\r
+ if (treeIndexes == null || treeIndexes.isEmpty()){\r
+ return result;\r
+ }\r
+\r
+ String hql = " SELECT tn.treeIndex, r.orderIndex "\r
+ + " FROM TaxonNode tn "\r
+ + " JOIN tn.taxon t "\r
+ + " JOIN t.name n "\r
+ + " JOIN n.rank r "\r
+ + " WHERE tn.treeIndex IN (:treeIndexes) ";\r
+ if (minRankOrderIndex != null){\r
+ hql += " AND r.orderIndex <= :minOrderIndex";\r
+ }\r
+ if (maxRankOrderIndex != null){\r
+ hql += " AND r.orderIndex >= :maxOrderIndex";\r
+ }\r
+\r
+ Query query = getSession().createQuery(hql);\r
+ query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));\r
+ if (minRankOrderIndex != null){\r
+ query.setParameter("minOrderIndex", minRankOrderIndex);\r
+ }\r
+ if (maxRankOrderIndex != null){\r
+ query.setParameter("maxOrderIndex", maxRankOrderIndex);\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ List<Object[]> list = query.list();\r
+ for (Object[] o : list){\r
+ result.put(TreeIndex.NewInstance((String)o[0]), (Integer)o[1]);\r
+ }\r
+ return result;\r
+ }\r
+\r
+ @Override\r
+ public Map<TreeIndex, UuidAndTitleCache<?>> taxonUuidsForTreeIndexes(Collection<TreeIndex> treeIndexes) {\r
+ Map<TreeIndex, UuidAndTitleCache<?>> result = new HashMap<>();\r
+ if (treeIndexes == null || treeIndexes.isEmpty()){\r
+ return result;\r
+ }\r
+\r
+ String hql =\r
+ " SELECT tn.treeIndex, t.uuid, tnb.titleCache "\r
+ + " FROM TaxonNode tn JOIN tn.taxon t Join t.name tnb "\r
+ + " WHERE tn.treeIndex IN (:treeIndexes) ";\r
+ Query query = getSession().createQuery(hql);\r
+ query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));\r
+\r
+ @SuppressWarnings("unchecked")\r
+ List<Object[]> list = query.list();\r
+ for (Object[] o : list){\r
+ result.put(TreeIndex.NewInstance((String)o[0]), new UuidAndTitleCache<>((UUID)o[1], null, (String)o[2]));\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ @Override\r
+ public TaxonNodeDto taxonNodeDtoParentRank(Classification classification, Rank rank, TaxonName name) {\r
+ \r
+ Set<Taxon> taxa = name.getTaxa();\r
+ TaxonNode node = null;\r
+ String treeIndex = null;\r
+ for (Taxon taxon:taxa) {\r
+ node = taxon.getTaxonNode(classification);\r
+ if (node != null) {\r
+ break;\r
+ }\r
+ }\r
+ if (node != null) {\r
+ treeIndex = node.treeIndex();\r
+ }\r
+ Criteria nodeCrit = getSession().createCriteria(TaxonNode.class);\r
+ Criteria taxonCrit = nodeCrit.createCriteria("taxon");\r
+ Criteria nameCrit = taxonCrit.createCriteria("name");\r
+ nodeCrit.add(Restrictions.eq("classification", classification));\r
+ nameCrit.add(Restrictions.eq("rank", rank));\r
+ \r
+ ProjectionList projList = Projections.projectionList();\r
+ projList.add(Projections.property("treeIndex"));\r
+ projList.add(Projections.property("uuid"));\r
+\r
+ @SuppressWarnings("unchecked")\r
+ List<Object[]> list = nodeCrit.list();\r
+ UUID uuid = null;\r
+ if (list.size() > 0) {\r
+ for (Object o: list) {\r
+ Object[] objectArray = (Object[]) o;\r
+ uuid = (UUID)objectArray[1];\r
+ String treeIndexParent = (String) objectArray[0];\r
+ if (treeIndex.startsWith(treeIndexParent)) {\r
+ node = load(uuid);\r
+ break;\r
+ }\r
+ }\r
+ TaxonNodeDto dto = new TaxonNodeDto(node);\r
+ return dto;\r
+ }\r
+ \r
+ return null;\r
+ }\r
+ \r
+ \r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public int countSecundumForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, Reference newSec,\r
+ boolean overwriteExisting, boolean includeSharedTaxa, boolean emptySecundumDetail) {\r
+ String queryStr = forSubtreeAcceptedQueryStr(includeSharedTaxa, subTreeIndex, false, SelectMode.COUNT);\r
+ if (!overwriteExisting){\r
+ queryStr += " AND t.sec IS NULL ";\r
+ }\r
+ return countResult(queryStr);\r
+ }\r
+ /**\r
+ * @param queryStr\r
+ * @return\r
+ */\r
+ private int countResult(String queryStr) {\r
+ Query query = getSession().createQuery(queryStr);\r
+ return ((Long)query.uniqueResult()).intValue();\r
+ }\r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public int countSecundumForSubtreeSynonyms(TreeIndex subTreeIndex, Reference newSec,\r
+ boolean overwriteExisting, boolean includeSharedTaxa, boolean emptySecundumDetail) {\r
+ String queryStr = forSubtreeSynonymQueryStr(includeSharedTaxa, subTreeIndex, false, SelectMode.COUNT);\r
+ if (!overwriteExisting){\r
+ queryStr += " AND syn.sec IS NULL ";\r
+ }\r
+ return countResult(queryStr);\r
+ }\r
+\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ //#3465\r
+ @Override\r
+ public Set<TaxonBase> setSecundumForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, Reference newSec,\r
+ boolean overwriteExisting, boolean includeSharedTaxa, boolean emptyDetail, IProgressMonitor monitor) {\r
+ //for some reason this does not work, maybe because the listeners are not activated,\r
+ //but also the first taxon for some reason does not get updated in terms of secundum, but only by the update listener\r
+// String where = "SELECT t.id FROM TaxonNode tn JOIN tn.taxon t " +\r
+// " WHERE tn.treeIndex like '%s%%' ORDER BY t.id";\r
+// where = String.format(where, subTreeIndex.toString());\r
+// Query query1 = getSession().createQuery(where);\r
+// List l = query1.list();\r
+//\r
+// String hql = "UPDATE Taxon SET sec = :newSec, publish=false WHERE id IN (" + where + ")";\r
+// Query query = getSession().createQuery(hql);\r
+// query.setParameter("newSec", newSec);\r
+// int n = query.executeUpdate();\r
+\r
+ String queryStr = forSubtreeAcceptedQueryStr(includeSharedTaxa, subTreeIndex, false, SelectMode.ID);\r
+ if (!overwriteExisting){\r
+ queryStr += " AND t.sec IS NULL ";\r
+ }\r
+ return setSecundum(newSec, emptyDetail, queryStr, monitor);\r
+\r
+ }\r
+\r
+ @Override\r
+ public Set<TaxonBase> setSecundumForSubtreeSynonyms(TreeIndex subTreeIndex, Reference newSec,\r
+ boolean overwriteExisting, boolean includeSharedTaxa, boolean emptyDetail, IProgressMonitor monitor) {\r
+\r
+ String queryStr = forSubtreeSynonymQueryStr(includeSharedTaxa, subTreeIndex, false, SelectMode.ID);\r
+ if (!overwriteExisting){\r
+ queryStr += " AND syn.sec IS NULL ";\r
+ }\r
+ return setSecundum(newSec, emptyDetail, queryStr, monitor);\r
+ }\r
+ /**\r
+ * @param newSec\r
+ * @param emptyDetail\r
+ * @param queryStr\r
+ * @param monitor\r
+ * @return\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+ private <T extends TaxonBase<?>> Set<T> setSecundum(Reference newSec, boolean emptyDetail, String queryStr, IProgressMonitor monitor) {\r
+ Set<T> result = new HashSet<>();\r
+ Query query = getSession().createQuery(queryStr);\r
+ List<List<Integer>> partitionList = splitIdList(query.list(), DEFAULT_PARTITION_SIZE);\r
+ for (List<Integer> taxonIdList : partitionList){\r
+ List<TaxonBase> taxonList = taxonDao.loadList(taxonIdList, null, null);\r
+ for (TaxonBase taxonBase : taxonList){\r
+ if (taxonBase != null){\r
+ taxonBase = taxonDao.load(taxonBase.getUuid());\r
+ taxonBase.setSec(newSec);\r
+ if (emptyDetail){\r
+ taxonBase.setSecMicroReference(null);\r
+ }\r
+ result.add((T)CdmBase.deproxy(taxonBase));\r
+ monitor.worked(1);\r
+ if (monitor.isCanceled()){\r
+ return result;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+\r
+ private List<List<Integer>> splitIdList(List<Integer> idList, Integer size){\r
+ List<List<Integer>> result = new ArrayList<>();\r
+ for (int i = 0; (i*size)<idList.size(); i++) {\r
+ int upper = Math.min((i+1)*size, idList.size());\r
+ result.add(idList.subList(i*size, upper));\r
+ }\r
+ return result;\r
+ }\r
+\r
+ @Override\r
+ public int countPublishForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, boolean publish, boolean includeSharedTaxa, boolean includeHybrids) {\r
+ String queryStr = forSubtreeAcceptedQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.COUNT);\r
+ queryStr += " AND t.publish != :publish ";\r
+ System.out.println(queryStr);\r
+ Query query = getSession().createQuery(queryStr);\r
+ query.setBoolean("publish", publish);\r
+ return ((Long)query.uniqueResult()).intValue();\r
+ }\r
+\r
+ @Override\r
+ public int countPublishForSubtreeSynonyms(TreeIndex subTreeIndex, boolean publish, boolean includeSharedTaxa, boolean includeHybrids) {\r
+ String queryStr = forSubtreeSynonymQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.COUNT);\r
+ queryStr += " AND syn.publish != :publish ";\r
+ Query query = getSession().createQuery(queryStr);\r
+ query.setBoolean("publish", publish);\r
+ return ((Long)query.uniqueResult()).intValue();\r
+ }\r
+\r
+ @Override\r
+ public Set<TaxonBase> setPublishForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, boolean publish,\r
+ boolean includeSharedTaxa, boolean includeHybrids, IProgressMonitor monitor) {\r
+ String queryStr = forSubtreeAcceptedQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.ID);\r
+ queryStr += " AND t.publish != :publish ";\r
+ return setPublish(publish, queryStr, null, monitor);\r
+ }\r
+\r
+ @Override\r
+ public Set<TaxonBase> setPublishForSubtreeSynonyms(TreeIndex subTreeIndex, boolean publish,\r
+ boolean includeSharedTaxa, boolean includeHybrids, IProgressMonitor monitor) {\r
+ String queryStr = forSubtreeSynonymQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.ID);\r
+ queryStr += " AND syn.publish != :publish ";\r
+ return setPublish(publish, queryStr, null, monitor);\r
+ }\r
+ @Override\r
+ public int countPublishForSubtreeRelatedTaxa(TreeIndex subTreeIndex, boolean publish, boolean includeSharedTaxa, boolean includeHybrids) {\r
+ String queryStr = forSubtreeRelatedTaxaQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.COUNT);\r
+ queryStr += " AND relTax.publish != :publish ";\r
+ Query query = getSession().createQuery(queryStr);\r
+ query.setBoolean("publish", publish);\r
+ return ((Long)query.uniqueResult()).intValue();\r
+ }\r
+\r
+ @Override\r
+ public Set<TaxonBase> setPublishForSubtreeRelatedTaxa(TreeIndex subTreeIndex, boolean publish,\r
+ Set<UUID> relationTypes, boolean includeSharedTaxa, boolean includeHybrids,\r
+ IProgressMonitor monitor) {\r
+ String queryStr = forSubtreeRelatedTaxaQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.ID);\r
+ queryStr += " AND relTax.publish != :publish ";\r
+ queryStr += " AND rel.type.uuid IN (:relTypeUuid)";\r
+ return setPublish(publish, queryStr, relationTypes, monitor);\r
+ }\r
+\r
+ private static final int DEFAULT_PARTITION_SIZE = 100;\r
+ /**\r
+ * @param publish\r
+ * @param queryStr\r
+ * @return\r
+ */\r
+ private <T extends TaxonBase<?>> Set<T> setPublish(boolean publish, String queryStr, Set<UUID> relTypeUuids, IProgressMonitor monitor) {\r
+ Set<T> result = new HashSet<>();\r
+ Query query = getSession().createQuery(queryStr);\r
+ query.setBoolean("publish", publish);\r
+ if (relTypeUuids != null && !relTypeUuids.isEmpty()){\r
+ query.setParameterList("relTypeUuid", relTypeUuids);\r
+ }\r
+ @SuppressWarnings("unchecked")\r
+ List<List<Integer>> partitionList = splitIdList(query.list(), DEFAULT_PARTITION_SIZE);\r
+ for (List<Integer> taxonIdList : partitionList){\r
+ List<TaxonBase> taxonList = taxonDao.loadList(taxonIdList, null, null);\r
+ for (TaxonBase taxonBase : taxonList){\r
+ if (taxonBase != null){\r
+ taxonBase.setPublish(publish);\r
+ result.add((T)CdmBase.deproxy(taxonBase));\r
+ monitor.worked(1);\r
+ if (monitor.isCanceled()){\r
+ return result;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+\r
+\r
+ /**\r
+ * @param includeSharedTaxa\r
+ * @param subTreeIndex\r
+ * @param includeHybrids\r
+ * @param includeSharedTaxa2\r
+ * @return\r
+ */\r
+ private String forSubtreeSynonymQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex, boolean excludeHybrids, SelectMode mode) {\r
+ String queryStr = "SELECT " + mode.hql("syn")\r
+ + " FROM TaxonNode tn "\r
+ + " JOIN tn.taxon t "\r
+ + " JOIN t.synonyms syn LEFT JOIN syn.name n ";\r
+ String whereStr = " tn.treeIndex LIKE '%1$s%%' ";\r
+ if (!includeSharedTaxa){\r
+ whereStr += " AND NOT EXISTS ("\r
+ + "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";\r
+ }\r
+ whereStr = handleExcludeHybrids(whereStr, excludeHybrids, "syn");\r
+ queryStr += " WHERE " + String.format(whereStr, subTreeIndex.toString());\r
+\r
+ return queryStr;\r
+ }\r
+\r
+ /**\r
+ * @param queryStr\r
+ * @param excludeHybrids\r
+ * @return\r
+ */\r
+ private String handleExcludeHybrids(String whereStr, boolean excludeHybrids, String t) {\r
+ if(excludeHybrids){\r
+\r
+ String hybridWhere = " AND (n is NULL OR "\r
+ + " (n.monomHybrid=0 AND n.binomHybrid=0 "\r
+ + " AND n.trinomHybrid=0 AND n.hybridFormula=0 )) ";\r
+\r
+ whereStr += hybridWhere; //String.format(hybridWhere, t);\r
+ }\r
+ return whereStr;\r
+ }\r
+\r
+ private String forSubtreeRelatedTaxaQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex,\r
+ boolean excludeHybrids, SelectMode mode) {\r
+ String queryStr = "SELECT " + mode.hql("relTax")\r
+ + " FROM TaxonNode tn "\r
+ + " JOIN tn.taxon t "\r
+ + " JOIN t.relationsToThisTaxon rel"\r
+ + " JOIN rel.relatedFrom relTax LEFT JOIN relTax.name n ";\r
+ String whereStr =" tn.treeIndex LIKE '%1$s%%' ";\r
+ if (!includeSharedTaxa){\r
+ //toTaxon should only be used in the given subtree\r
+ whereStr += " AND NOT EXISTS ("\r
+ + "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";\r
+ //from taxon should not be used in another classification\r
+ whereStr += " AND NOT EXISTS ("\r
+ + "FROM TaxonNode tn3 WHERE tn3.taxon = relTax AND tn3.treeIndex not like '%1$s%%') ";\r
+ //fromTaxon should not be related as e.g. pro parte synonym or misapplication to\r
+ //another taxon which is not part of the subtree\r
+ //TODO and has not the publish state\r
+ whereStr += " AND NOT EXISTS ("\r
+ + "FROM TaxonNode tn4 JOIN tn4.taxon t2 JOIN t2.relationsToThisTaxon rel2 "\r
+ + " WHERE rel2.relatedFrom = relTax AND tn4.treeIndex not like '%1$s%%' "\r
+ + " AND tn4.taxon.publish != :publish ) ";\r
+ }\r
+ whereStr = handleExcludeHybrids(whereStr, excludeHybrids, "relTax");\r
+ queryStr += " WHERE " + String.format(whereStr, subTreeIndex.toString());\r
+\r
+ return queryStr;\r
+ }\r
+\r
+ private enum SelectMode{\r
+ COUNT(" count(*) "),\r
+ ID ("id "),\r
+ UUID("uuid "),\r
+ FULL("");\r
+ private String hql;\r
+ SelectMode(String hql){\r
+ this.hql = hql;\r
+ }\r
+ public String hql(String prefix){\r
+ switch (this){\r
+ case ID:\r
+ case UUID:\r
+ return CdmUtils.Nz(prefix)+"." + hql;\r
+ case FULL:\r
+ return CdmUtils.Nz(prefix) + hql;\r
+ case COUNT:\r
+ default: return hql;\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ private String forSubtreeAcceptedQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex, boolean excludeHybrids, SelectMode mode) {\r
+ String queryStr = "SELECT " + mode.hql("t")\r
+ + " FROM TaxonNode tn JOIN tn.taxon t LEFT JOIN t.name n ";\r
+ String whereStr = " tn.treeIndex like '%1$s%%' ";\r
+ if (!includeSharedTaxa){\r
+ whereStr += " AND NOT EXISTS ("\r
+ + "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";\r
+ }\r
+ whereStr = handleExcludeHybrids(whereStr, excludeHybrids, "t");\r
+ queryStr += " WHERE " + String.format(whereStr, subTreeIndex.toString());\r
+\r
+ return queryStr;\r
+ }\r
+\r
+ @Override\r
+ public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, Integer limit, String pattern, boolean searchForClassifications) {\r
+ int classificationId = classification.getId();\r
+\r
+ String queryString =\r
+ " SELECT nodes.uuid, nodes.id, taxon.titleCache, taxon.name.rank " +\r
+ " FROM TaxonNode AS nodes "\r
+ + " JOIN nodes.taxon as taxon " +\r
+ " WHERE nodes.classification.id = " + classificationId ;\r
+ if (pattern != null){\r
+ if (pattern.equals("?")){\r
+ limit = null;\r
+ } else{\r
+ if (!pattern.endsWith("*")){\r
+ pattern += "%";\r
+ }\r
+ pattern = pattern.replace("*", "%");\r
+ pattern = pattern.replace("?", "%");\r
+ queryString = queryString + " AND taxon.titleCache LIKE (:pattern) " ;\r
+ }\r
+ }\r
+\r
+ Query query = getSession().createQuery(queryString);\r
+\r
+ if (limit != null){\r
+ query.setMaxResults(limit);\r
+ }\r
+\r
+ if (pattern != null && !pattern.equals("?")){\r
+ query.setParameter("pattern", pattern);\r
+ }\r
+ @SuppressWarnings("unchecked")\r
+ List<Object[]> result = query.list();\r
+\r
+ if (searchForClassifications){\r
+ queryString = ""\r
+ + " SELECT nodes.uuid, nodes.id, nodes.classification.titleCache, NULLIF(1,1) "\r
+ + " FROM TaxonNode AS nodes "\r
+ + " WHERE nodes.classification.id = " + classificationId +\r
+ " AND nodes.taxon IS NULL";\r
+ if (pattern != null){\r
+ if (pattern.equals("?")){\r
+ limit = null;\r
+ } else{\r
+ if (!pattern.endsWith("*")){\r
+ pattern += "%";\r
+ }\r
+ pattern = pattern.replace("*", "%");\r
+ pattern = pattern.replace("?", "%");\r
+ queryString = queryString + " AND nodes.classification.titleCache LIKE (:pattern) " ;\r
+ }\r
+ }\r
+ query = getSession().createQuery(queryString);\r
+\r
+ if (limit != null){\r
+ query.setMaxResults(limit);\r
+ }\r
+\r
+ if (pattern != null && !pattern.equals("?")){\r
+ query.setParameter("pattern", pattern);\r
+ }\r
+ @SuppressWarnings("unchecked")\r
+ List<Object[]> resultClassifications = query.list();\r
+\r
+ result.addAll(resultClassifications);\r
+ }\r
+\r
+ if(result.size() == 0){\r
+ return null;\r
+ }else{\r
+ List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>(result.size());\r
+ if (result.iterator().next().length == 4){\r
+ Collections.sort(result, new UuidAndTitleCacheTaxonComparator());\r
+ }\r
+ for (Object object : result){\r
+ Object[] objectArray = (Object[]) object;\r
+ UUID uuid = (UUID)objectArray[0];\r
+ Integer id = (Integer) objectArray[1];\r
+ String titleCache = (String) objectArray[2];\r
+\r
+ list.add(new UuidAndTitleCache<>(TaxonNode.class, uuid, id, titleCache));\r
+ }\r
+\r
+ return list;\r
+ }\r
+ }\r
+\r
\r
}\r