2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.persistence
.dao
.hibernate
.taxon
;
12 import java
.math
.BigInteger
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collection
;
15 import java
.util
.Collections
;
16 import java
.util
.Comparator
;
17 import java
.util
.HashMap
;
18 import java
.util
.HashSet
;
19 import java
.util
.Iterator
;
20 import java
.util
.List
;
23 import java
.util
.UUID
;
25 import org
.apache
.log4j
.Logger
;
26 import org
.hibernate
.Criteria
;
27 import org
.hibernate
.Hibernate
;
28 import org
.hibernate
.Query
;
29 import org
.hibernate
.criterion
.Projections
;
30 import org
.hibernate
.criterion
.Restrictions
;
31 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
32 import org
.springframework
.beans
.factory
.annotation
.Qualifier
;
33 import org
.springframework
.stereotype
.Repository
;
35 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
36 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
37 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
38 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
39 import eu
.etaxonomy
.cdm
.model
.common
.TreeIndex
;
40 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
41 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
42 import eu
.etaxonomy
.cdm
.model
.reference
.NamedSource
;
43 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
44 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
45 import eu
.etaxonomy
.cdm
.model
.taxon
.SecundumSource
;
46 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
47 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
48 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
49 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
50 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeAgentRelation
;
51 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
52 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.Restriction
;
53 import eu
.etaxonomy
.cdm
.persistence
.dao
.hibernate
.common
.AnnotatableDaoImpl
;
54 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.IClassificationDao
;
55 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
56 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonNodeDao
;
57 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonRelationshipDao
;
58 import eu
.etaxonomy
.cdm
.persistence
.dto
.SortableTaxonNodeQueryResult
;
59 import eu
.etaxonomy
.cdm
.persistence
.dto
.SortableTaxonNodeQueryResultComparator
;
60 import eu
.etaxonomy
.cdm
.persistence
.dto
.TaxonNodeDto
;
61 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
62 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
69 @Qualifier("taxonNodeDaoHibernateImpl")
70 public class TaxonNodeDaoHibernateImpl
extends AnnotatableDaoImpl
<TaxonNode
>
71 implements ITaxonNodeDao
{
73 private static final Logger logger
= Logger
.getLogger(TaxonNodeDaoHibernateImpl
.class);
75 private static final int DEFAULT_SET_SUBTREE_PARTITION_SIZE
= 100;
78 private ITaxonDao taxonDao
;
80 private IClassificationDao classificationDao
;
82 private ITaxonRelationshipDao taxonRelDao
;
84 public TaxonNodeDaoHibernateImpl() {
85 super(TaxonNode
.class);
89 public UUID
delete(TaxonNode persistentObject
, boolean deleteChildren
){
90 Taxon taxon
= persistentObject
.getTaxon();
91 taxon
= HibernateProxyHelper
.deproxy(taxon
);
93 /*Session session = this.getSession();
94 Query query = session.createQuery("from TaxonNode t where t.taxon = :taxon");
95 query.setParameter("taxon", taxon);
96 List result = query.list();*/
98 Hibernate
.initialize(taxon
);
99 Hibernate
.initialize(taxon
.getTaxonNodes());
100 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
101 //Hibernate.initialize(taxon.getTaxonNodes());
102 for (TaxonNode node
:nodes
) {
103 node
= HibernateProxyHelper
.deproxy(node
);
105 if (node
.equals(persistentObject
)){
106 if (node
.hasChildNodes()){
107 Iterator
<TaxonNode
> childNodes
= node
.getChildNodes().iterator();
109 List
<TaxonNode
> listForDeletion
= new ArrayList
<>();
110 while (childNodes
.hasNext()){
111 childNode
= childNodes
.next();
112 listForDeletion
.add(childNode
);
116 for (TaxonNode deleteNode
:listForDeletion
){
117 delete(deleteNode
, deleteChildren
);
121 taxon
.removeTaxonNode(node
, deleteChildren
);
122 taxonDao
.saveOrUpdate(taxon
);
123 taxon
= HibernateProxyHelper
.deproxy(taxonDao
.findByUuid(taxon
.getUuid()), Taxon
.class);
124 taxonDao
.delete(taxon
);
130 UUID result
= super.delete(persistentObject
);
135 public List
<TaxonNode
> getTaxonOfAcceptedTaxaByClassification(Classification classification
, Integer start
, Integer end
) {
136 int classificationId
= classification
.getId();
138 if(start
!=null && end
!= null){
139 limit
= "LIMIT "+start
+"," +end
;
142 String queryString
= "SELECT DISTINCT nodes.*,taxa.titleCache "
143 + " FROM TaxonNode AS nodes "
144 + " LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id "
145 + " WHERE taxa.DTYPE = 'Taxon' "
146 + " AND nodes.classification_id = " + classificationId
+
147 " ORDER BY taxa.titleCache " + limit
;
148 @SuppressWarnings("unchecked")
149 List
<TaxonNode
> result
= getSession().createSQLQuery(queryString
).addEntity(TaxonNode
.class).list();
155 public int countTaxonOfAcceptedTaxaByClassification(Classification classification
){
156 int classificationId
= classification
.getId();
158 String queryString
= ""
159 + " SELECT DISTINCT COUNT('nodes.*') "
160 + " FROM TaxonNode AS nodes "
161 + " LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id "
162 + " WHERE taxa.DTYPE = 'Taxon' AND nodes.classification_id = " + classificationId
;
163 @SuppressWarnings("unchecked")
164 List
<BigInteger
> result
= getSession().createSQLQuery(queryString
).list();
165 return result
.get(0).intValue ();
169 public List
<TaxonNodeDto
> listChildNodesAsUuidAndTitleCache(TaxonNodeDto parent
) {
171 " SELECT tn.uuid, tn.id, t.titleCache "
172 + " FROM TaxonNode tn "
173 + " INNER JOIN tn.taxon AS t "
174 + " WHERE tn.parent.uuid = :parentId";
176 Query query
= getSession().createQuery(queryString
);
177 query
.setParameter("parentId", parent
.getUuid());
179 @SuppressWarnings("unchecked")
180 List
<Object
[]> result
= query
.list();
182 List
<TaxonNodeDto
> list
= new ArrayList
<>();
183 for(Object
[] object
: result
){
184 list
.add(new TaxonNodeDto((UUID
) object
[0],(Integer
) object
[1], (String
) object
[2]));
190 public List
<TaxonNodeDto
> listChildNodesAsTaxonNodeDto(TaxonNodeDto parent
) {
193 + " FROM TaxonNode tn "
194 + " INNER JOIN tn.taxon AS t "
195 + " WHERE tn.parent.uuid = :parentId";
196 Query query
= getSession().createQuery(queryString
);
197 query
.setParameter("parentId", parent
.getUuid());
199 @SuppressWarnings("unchecked")
200 List
<TaxonNode
> result
= query
.list();
202 List
<TaxonNodeDto
> list
= new ArrayList
<>();
203 for(TaxonNode object
: result
){
204 list
.add(new TaxonNodeDto(object
));
210 public List
<TaxonNodeDto
> getUuidAndTitleCache(Integer limit
, String pattern
, UUID classificationUuid
, boolean includeDoubtful
) {
212 Query query
= createQueryForUuidAndTitleCache(limit
, classificationUuid
, pattern
, includeDoubtful
);
213 @SuppressWarnings("unchecked")
214 List
<SortableTaxonNodeQueryResult
> result
= query
.list();
215 Collections
.sort(result
, new SortableTaxonNodeQueryResultComparator());
216 if(logger
.isTraceEnabled()){
217 logger
.trace("number of matches:" + result
.size());
218 result
.stream().forEach(o
-> logger
.trace("uuid: " + o
.getTaxonNodeUuid() + " titleCache:" + o
.getTaxonTitleCache() + " rank: " + o
.getNameRank()));
220 List
<TaxonNodeDto
> list
= new ArrayList
<>();
221 // int index = limit;
222 for(SortableTaxonNodeQueryResult stnqr
: result
){
224 list
.add(new TaxonNodeDto(stnqr
.getTaxonNodeUuid(),stnqr
.getTaxonNodeId(), stnqr
.getTaxonTitleCache()));
233 private Query
createQueryForUuidAndTitleCache(Integer limit
, UUID classificationUuid
, String pattern
, boolean includeDoubtful
){
234 String doubtfulPattern
= "";
235 String queryString
= "SELECT new " + SortableTaxonNodeQueryResult
.class.getName() + "("
236 + " node.uuid, node.id, t.titleCache, rank"
238 + " FROM TaxonNode AS node "
239 + " JOIN node.taxon as t " // FIXME why not inner join here?
240 + " INNER JOIN t.name AS name "
241 + " LEFT OUTER JOIN name.rank AS rank "
244 if (classificationUuid
!= null){
245 queryString
= queryString
+ " node.classification.uuid like :classificationUuid " ;
247 if (pattern
!= null){
248 if (pattern
.equals("?")){
251 if (!pattern
.endsWith("*")){
254 pattern
= pattern
.replace("*", "%");
255 pattern
= pattern
.replace("?", "%");
256 if (classificationUuid
!= null){
257 queryString
= queryString
+ " AND ";
259 queryString
= queryString
+ " (t.titleCache LIKE (:pattern) " ;
260 doubtfulPattern
= "?" + pattern
;
261 if (includeDoubtful
){
262 queryString
= queryString
+ " OR t.titleCache LIKE (:doubtfulPattern))";
264 queryString
= queryString
+ ")";
270 Query query
= getSession().createQuery(queryString
);
271 if (pattern
!= null){
272 query
.setParameter("pattern", pattern
);
274 if (includeDoubtful
){
275 query
.setParameter("doubtfulPattern", doubtfulPattern
);
278 if(classificationUuid
!= null){
279 query
.setParameter("classificationUuid", classificationUuid
);
282 query
.setMaxResults(limit
);
290 public TaxonNodeDto
getParentUuidAndTitleCache(TaxonNodeDto child
) {
291 String queryString
= ""
292 + " SELECT tn.parent.uuid, tn.parent.id, tn.parent.taxon.titleCache, "
293 + " tn.parent.classification.titleCache "
294 + " FROM TaxonNode tn"
295 + " LEFT OUTER JOIN tn.parent.taxon"
296 + " WHERE tn.id = :childId";
297 Query query
= getSession().createQuery(queryString
);
298 query
.setParameter("childId", child
.getId());
299 List
<TaxonNodeDto
> list
= new ArrayList
<>();
301 @SuppressWarnings("unchecked")
302 List
<Object
[]> result
= query
.list();
304 for(Object
[] object
: result
){
305 UUID uuid
= (UUID
) object
[0];
306 Integer id
= (Integer
) object
[1];
307 String taxonTitleCache
= (String
) object
[2];
308 String classificationTitleCache
= (String
) object
[3];
309 if(taxonTitleCache
!=null){
310 list
.add(new TaxonNodeDto(uuid
,id
, taxonTitleCache
));
313 list
.add(new TaxonNodeDto(uuid
,id
, classificationTitleCache
));
317 return list
.iterator().next();
322 public List
<TaxonNode
> listChildrenOf(TaxonNode node
, Integer pageSize
, Integer pageIndex
,
323 boolean recursive
, boolean includeUnpublished
, List
<String
> propertyPaths
, Comparator
<TaxonNode
> comparator
){
324 return listChildrenOfRecursive(node
,new ArrayList
<>(), pageSize
, pageIndex
, recursive
, includeUnpublished
, propertyPaths
, comparator
);
327 private List
<TaxonNode
> listChildrenOfRecursive(TaxonNode node
, List
<TaxonNode
> previousResult
, Integer pageSize
, Integer pageIndex
,
328 boolean recursive
, boolean includeUnpublished
, List
<String
> propertyPaths
, Comparator
<TaxonNode
> comparator
){
330 if (recursive
== true && comparator
== null ){
331 Criteria crit
= childrenOfCriteria(node
, includeUnpublished
);
333 this.addPageSizeAndNumber(crit
, pageSize
, pageIndex
);
334 @SuppressWarnings("unchecked")
335 List
<TaxonNode
> results
= crit
.list();
336 results
.remove(node
);
337 defaultBeanInitializer
.initializeAll(results
, propertyPaths
);
340 } else if (recursive
== true){
341 List
<TaxonNode
> children
= node
.getChildNodes();
342 Collections
.sort(children
, comparator
);
343 for (TaxonNode child
: children
){
344 if (!previousResult
.contains(child
)){
345 previousResult
.add(child
);
347 if (child
.hasChildNodes()){
348 previousResult
= listChildrenOfRecursive(child
, previousResult
, pageSize
, pageIndex
,
349 recursive
, includeUnpublished
, propertyPaths
, comparator
);
352 return previousResult
;
355 return classificationDao
.listChildrenOf(node
.getTaxon(), node
.getClassification(), null,
356 includeUnpublished
, pageSize
, pageIndex
, propertyPaths
);
361 public Long
countChildrenOf(TaxonNode node
, Classification classification
,
362 boolean recursive
, boolean includeUnpublished
) {
364 if (recursive
== true){
365 Criteria crit
= childrenOfCriteria(node
, includeUnpublished
);
366 crit
.setProjection(Projections
.rowCount());
367 return ((Integer
)crit
.uniqueResult().hashCode()).longValue();
369 return classificationDao
.countChildrenOf(
370 node
.getTaxon(), classification
, null, includeUnpublished
);
374 private Criteria
childrenOfCriteria(TaxonNode node
, boolean includeUnpublished
) {
375 Criteria crit
= getSession().createCriteria(TaxonNode
.class);
376 crit
.add( Restrictions
.like("treeIndex", node
.treeIndex()+ "%") );
377 if (!includeUnpublished
){
378 crit
.createCriteria("taxon").add( Restrictions
.eq("publish", Boolean
.TRUE
));
384 public List
<TaxonNodeAgentRelation
> listTaxonNodeAgentRelations(UUID taxonUuid
, UUID classificationUuid
,
385 UUID agentUuid
, UUID rankUuid
, UUID relTypeUuid
, Integer start
, Integer limit
,
386 List
<String
> propertyPaths
) {
388 StringBuilder hql
= prepareListTaxonNodeAgentRelations(taxonUuid
, classificationUuid
,
389 agentUuid
, rankUuid
, relTypeUuid
, false);
391 Query query
= getSession().createQuery(hql
.toString());
394 query
.setMaxResults(limit
);
396 query
.setFirstResult(start
);
400 setParamsForListTaxonNodeAgentRelations(taxonUuid
, classificationUuid
, agentUuid
, rankUuid
, relTypeUuid
, query
);
402 @SuppressWarnings("unchecked")
403 List
<TaxonNodeAgentRelation
> records
= query
.list();
405 if(propertyPaths
!= null) {
406 defaultBeanInitializer
.initializeAll(records
, propertyPaths
);
412 public <S
extends TaxonNode
> List
<S
> list(Class
<S
> type
, List
<Restriction
<?
>> restrictions
, Integer limit
,
413 Integer start
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
414 // TODO Auto-generated method stub
415 return list(type
, restrictions
, limit
, start
, orderHints
, propertyPaths
, INCLUDE_UNPUBLISHED
);
419 public <S
extends TaxonNode
> List
<S
> list(Class
<S
> type
, List
<Restriction
<?
>> restrictions
, Integer limit
,
420 Integer start
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, boolean includePublished
) {
422 Criteria criteria
= createCriteria(type
, restrictions
, false);
424 if(!includePublished
){
425 criteria
.add(Restrictions
.eq("taxon.publish", true));
428 addLimitAndStart(criteria
, limit
, start
);
429 addOrder(criteria
, orderHints
);
431 @SuppressWarnings("unchecked")
432 List
<S
> result
= criteria
.list();
433 defaultBeanInitializer
.initializeAll(result
, propertyPaths
);
438 public long count(Class
<?
extends TaxonNode
> type
, List
<Restriction
<?
>> restrictions
) {
439 return count(type
, restrictions
, INCLUDE_UNPUBLISHED
);
444 public long count(Class
<?
extends TaxonNode
> type
, List
<Restriction
<?
>> restrictions
, boolean includePublished
) {
446 Criteria criteria
= createCriteria(type
, restrictions
, false);
447 if(!includePublished
){
448 criteria
.add(Restrictions
.eq("taxon.publish", true));
450 criteria
.setProjection(Projections
.projectionList().add(Projections
.rowCount()));
451 return (Long
) criteria
.uniqueResult();
455 public long countTaxonNodeAgentRelations(UUID taxonUuid
, UUID classificationUuid
, UUID agentUuid
, UUID rankUuid
, UUID relTypeUuid
) {
457 StringBuilder hql
= prepareListTaxonNodeAgentRelations(taxonUuid
, classificationUuid
, agentUuid
, rankUuid
, relTypeUuid
, true);
458 Query query
= getSession().createQuery(hql
.toString());
460 setParamsForListTaxonNodeAgentRelations(taxonUuid
, classificationUuid
, agentUuid
, rankUuid
, relTypeUuid
, query
);
462 Long count
= Long
.parseLong(query
.uniqueResult().toString());
469 * @param classificationUuid
471 * @param relTypeUuid TODO
472 * @param doCount TODO
474 * limit to taxa having this rank, only applies if <code>taxonUuid = null</code>
477 private StringBuilder
prepareListTaxonNodeAgentRelations(UUID taxonUuid
, UUID classificationUuid
, UUID agentUuid
, UUID rankUuid
, UUID relTypeUuid
, boolean doCount
) {
479 StringBuilder hql
= new StringBuilder();
481 String join_fetch_mode
= doCount ?
"JOIN" : "JOIN FETCH";
484 hql
.append("SELECT COUNT(tnar)");
486 hql
.append("SELECT tnar");
489 hql
.append(" FROM TaxonNodeAgentRelation AS tnar ");
490 if(taxonUuid
!= null) {
491 // taxonUuid is search filter, do not fetch it
492 hql
.append(" JOIN tnar.taxonNode AS tn "
493 + " JOIN tn.taxon AS t ");
495 hql
.append(join_fetch_mode
)
496 .append(" tnar.taxonNode AS tn ")
497 .append(join_fetch_mode
).append(" tn.taxon AS t ");
498 if(rankUuid
!= null) {
499 hql
.append(" join t.name as n ");
502 hql
.append(" JOIN tn.classification AS c ");
503 if(agentUuid
!= null) {
504 // agentUuid is search filter, do not fetch it
505 // hql.append(" join tnar.agent as a ");
506 hql
.append(join_fetch_mode
).append(" tnar.agent AS a ");
508 hql
.append(join_fetch_mode
).append(" tnar.agent AS a ");
511 hql
.append(" WHERE (1 = 1) ");
513 if(relTypeUuid
!= null) {
514 hql
.append(" AND tnar.type.uuid = :relTypeUuid ");
517 if(taxonUuid
!= null) {
518 hql
.append(" AND t.uuid = :taxonUuid ");
520 if(rankUuid
!= null) {
521 hql
.append(" AND n.rank.uuid = :rankUuid ");
524 if(classificationUuid
!= null) {
525 hql
.append(" AND c.uuid = :classificationUuid ");
527 if(agentUuid
!= null) {
528 hql
.append(" AND a.uuid = :agentUuid ");
531 hql
.append(" ORDER BY a.titleCache");
537 * @param classificationUuid
539 * @param relTypeUuid TODO
543 private void setParamsForListTaxonNodeAgentRelations(UUID taxonUuid
, UUID classificationUuid
, UUID agentUuid
,
544 UUID rankUuid
, UUID relTypeUuid
, Query query
) {
546 if(taxonUuid
!= null) {
547 query
.setParameter("taxonUuid", taxonUuid
);
549 if(rankUuid
!= null) {
550 query
.setParameter("rankUuid", rankUuid
);
553 if(classificationUuid
!= null) {
554 query
.setParameter("classificationUuid", classificationUuid
);
556 if(agentUuid
!= null) {
557 query
.setParameter("agentUuid", agentUuid
);
559 if(relTypeUuid
!= null) {
560 query
.setParameter("relTypeUuid", relTypeUuid
);
565 public Map
<TreeIndex
, Integer
> rankOrderIndexForTreeIndex(List
<TreeIndex
> treeIndexes
,
566 Integer minRankOrderIndex
,
567 Integer maxRankOrderIndex
) {
569 Map
<TreeIndex
, Integer
> result
= new HashMap
<>();
570 if (treeIndexes
== null || treeIndexes
.isEmpty()){
574 String hql
= " SELECT tn.treeIndex, r.orderIndex "
575 + " FROM TaxonNode tn "
576 + " JOIN tn.taxon t "
579 + " WHERE tn.treeIndex IN (:treeIndexes) ";
580 if (minRankOrderIndex
!= null){
581 hql
+= " AND r.orderIndex <= :minOrderIndex";
583 if (maxRankOrderIndex
!= null){
584 hql
+= " AND r.orderIndex >= :maxOrderIndex";
587 Query query
= getSession().createQuery(hql
);
588 query
.setParameterList("treeIndexes", TreeIndex
.toString(treeIndexes
));
589 if (minRankOrderIndex
!= null){
590 query
.setParameter("minOrderIndex", minRankOrderIndex
);
592 if (maxRankOrderIndex
!= null){
593 query
.setParameter("maxOrderIndex", maxRankOrderIndex
);
596 @SuppressWarnings("unchecked")
597 List
<Object
[]> list
= query
.list();
598 for (Object
[] o
: list
){
599 result
.put(TreeIndex
.NewInstance((String
)o
[0]), (Integer
)o
[1]);
605 public Map
<TreeIndex
, UuidAndTitleCache
<?
>> taxonUuidsForTreeIndexes(Collection
<TreeIndex
> treeIndexes
) {
606 Map
<TreeIndex
, UuidAndTitleCache
<?
>> result
= new HashMap
<>();
607 if (treeIndexes
== null || treeIndexes
.isEmpty()){
612 " SELECT tn.treeIndex, t.uuid, tnb.titleCache "
613 + " FROM TaxonNode tn JOIN tn.taxon t Join t.name tnb "
614 + " WHERE tn.treeIndex IN (:treeIndexes) ";
615 Query query
= getSession().createQuery(hql
);
616 query
.setParameterList("treeIndexes", TreeIndex
.toString(treeIndexes
));
618 @SuppressWarnings("unchecked")
619 List
<Object
[]> list
= query
.list();
620 for (Object
[] o
: list
){
621 result
.put(TreeIndex
.NewInstance((String
)o
[0]), new UuidAndTitleCache
<>((UUID
)o
[1], null, (String
)o
[2]));
627 public List
<TaxonNodeDto
> getParentTaxonNodeDtoForRank(
628 Classification classification
, Rank rank
, TaxonBase
<?
> taxonBase
) {
631 if (taxonBase
instanceof Taxon
) {
632 taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
634 taxon
= CdmBase
.deproxy(((Synonym
)taxonBase
).getAcceptedTaxon());
636 TaxonNode node
= null;
638 node
= taxon
.getTaxonNode(classification
);
640 List
<TaxonNodeDto
> result
= new ArrayList
<>();
642 String treeIndex
= node
.treeIndex();
643 List
<Integer
> ancestorNodeIds
= TreeIndex
.NewInstance(treeIndex
).parentNodeIds(false);
645 Criteria nodeCrit
= getSession().createCriteria(TaxonNode
.class);
646 Criteria taxonCrit
= nodeCrit
.createCriteria("taxon");
647 Criteria nameCrit
= taxonCrit
.createCriteria("name");
648 nodeCrit
.add(Restrictions
.in("id", ancestorNodeIds
));
649 nodeCrit
.add(Restrictions
.eq("classification", classification
));
650 nameCrit
.add(Restrictions
.eq("rank", rank
));
652 @SuppressWarnings("unchecked")
653 List
<TaxonNode
> list
= nodeCrit
.list();
654 for (TaxonNode rankNode
: list
){
655 TaxonNodeDto dto
= new TaxonNodeDto(rankNode
);
664 public List
<TaxonNodeDto
> getParentTaxonNodeDtoForRank(
665 Classification classification
, Rank rank
, TaxonName name
) {
667 Set
<TaxonBase
> taxa
= name
.getTaxonBases();
668 List
<TaxonNodeDto
> result
= new ArrayList
<>();
669 for (TaxonBase
<?
> taxonBase
:taxa
) {
670 List
<TaxonNodeDto
> tmpList
= getParentTaxonNodeDtoForRank(classification
, rank
, taxonBase
);
671 for (TaxonNodeDto tmpDto
: tmpList
){
672 boolean exists
= false; //an equal method does not yet exist for TaxonNodeDto therefore this workaround
673 for (TaxonNodeDto dto
: result
){
674 if (dto
.getTreeIndex().equals(tmpDto
.getTreeIndex())){
687 public int countSecundumForSubtreeAcceptedTaxa(TreeIndex subTreeIndex
, Reference newSec
,
688 boolean overwriteExisting
, boolean includeSharedTaxa
, boolean emptySecundumDetail
) {
689 String queryStr
= forSubtreeAcceptedQueryStr(includeSharedTaxa
, subTreeIndex
, false, SelectMode
.COUNT
);
690 if (!overwriteExisting
){
691 queryStr
+= " AND t.secSource.citation IS NULL ";
693 return countResult(queryStr
);
696 private int countResult(String queryStr
) {
697 Query query
= getSession().createQuery(queryStr
);
698 return ((Long
)query
.uniqueResult()).intValue();
702 public int countSecundumForSubtreeSynonyms(TreeIndex subTreeIndex
, Reference newSec
,
703 boolean overwriteExisting
, boolean includeSharedTaxa
, boolean emptySecundumDetail
) {
704 String queryStr
= forSubtreeSynonymQueryStr(includeSharedTaxa
, subTreeIndex
, false, SelectMode
.COUNT
);
705 if (!overwriteExisting
){
706 queryStr
+= " AND syn.secSource.citation IS NULL ";
708 return countResult(queryStr
);
712 public int countSecundumForSubtreeRelations(TreeIndex subTreeIndex
, Reference newSec
,
713 boolean overwriteExisting
, boolean includeSharedTaxa
, boolean emptySecundumDetail
) {
714 String queryStr
= forSubtreeRelationQueryStr(includeSharedTaxa
, overwriteExisting
, subTreeIndex
, SelectMode
.COUNT
);
715 return countResult(queryStr
);
720 public Set
<CdmBase
> setSecundumForSubtreeAcceptedTaxa(TreeIndex subTreeIndex
, Reference newSec
,
721 boolean overwriteExisting
, boolean includeSharedTaxa
, boolean emptyDetail
, IProgressMonitor monitor
) {
722 //for some reason this does not work, maybe because the listeners are not activated,
723 //but also the first taxon for some reason does not get updated in terms of secundum, but only by the update listener
724 // String where = "SELECT t.id FROM TaxonNode tn JOIN tn.taxon t " +
725 // " WHERE tn.treeIndex like '%s%%' ORDER BY t.id";
726 // where = String.format(where, subTreeIndex.toString());
727 // Query query1 = getSession().createQuery(where);
728 // List l = query1.list();
730 // String hql = "UPDATE Taxon SET sec = :newSec, publish=false WHERE id IN (" + where + ")";
731 // Query query = getSession().createQuery(hql);
732 // query.setParameter("newSec", newSec);
733 // int n = query.executeUpdate();
735 String queryStr
= forSubtreeAcceptedQueryStr(includeSharedTaxa
, subTreeIndex
, false, SelectMode
.ID
);
736 if (!overwriteExisting
){
737 queryStr
+= " AND t.secSource.citation IS NULL ";
739 return setSecundum(newSec
, emptyDetail
, queryStr
, monitor
);
743 public Set
<CdmBase
> setSecundumForSubtreeSynonyms(TreeIndex subTreeIndex
, Reference newSec
,
744 boolean overwriteExisting
, boolean includeSharedTaxa
, boolean emptyDetail
, IProgressMonitor monitor
) {
746 String queryStr
= forSubtreeSynonymQueryStr(includeSharedTaxa
, subTreeIndex
, false, SelectMode
.ID
);
747 if (!overwriteExisting
){
748 queryStr
+= " AND syn.secSource.citation IS NULL ";
750 return setSecundum(newSec
, emptyDetail
, queryStr
, monitor
);
753 private <T
extends TaxonBase
<?
>> Set
<CdmBase
> setSecundum(Reference newSec
, boolean emptyDetail
, String queryStr
, IProgressMonitor monitor
) {
754 Set
<CdmBase
> result
= new HashSet
<>();
755 Query query
= getSession().createQuery(queryStr
);
756 @SuppressWarnings("unchecked")
757 List
<List
<Integer
>> partitionList
= splitIdList(query
.list(), DEFAULT_SET_SUBTREE_PARTITION_SIZE
);
758 for (List
<Integer
> taxonIdList
: partitionList
){
759 @SuppressWarnings({ "unchecked", "rawtypes" })
760 List
<T
> taxonList
= (List
)taxonDao
.loadList(taxonIdList
, null, null);
761 for (T taxonBase
: taxonList
){
762 if (taxonBase
!= null){
763 taxonBase
= CdmBase
.deproxy(taxonBase
);
764 SecundumSource secSourceBefore
= taxonBase
.getSecSource();
765 Reference refBefore
= taxonBase
.getSec();
766 String refDetailBefore
= taxonBase
.getSecMicroReference();
767 if (newSec
== null && taxonBase
.getSec() !=null
768 || newSec
!= null && (taxonBase
.getSec() == null || !newSec
.equals(taxonBase
.getSec()) )){
769 taxonBase
.setSec(newSec
);
772 if (taxonBase
.getSecMicroReference() != null){
773 taxonBase
.setSecMicroReference(null);
776 //compute updated objects
777 SecundumSource secSourceAfter
= taxonBase
.getSecSource();
778 if (!CdmUtils
.nullSafeEqual(secSourceBefore
, secSourceAfter
)){
779 result
.add(taxonBase
);
780 }else if (secSourceBefore
!= null && secSourceBefore
.equals(secSourceAfter
)
781 && (!CdmUtils
.nullSafeEqual(refBefore
, secSourceAfter
.getCitation())
782 || !CdmUtils
.nullSafeEqual(refDetailBefore
, secSourceAfter
.getCitationMicroReference()))
784 result
.add(secSourceBefore
);
788 if (monitor
.isCanceled()){
793 commitAndRestartTransaction(newSec
);
794 monitor
.worked(taxonIdList
.size());
799 private void commitAndRestartTransaction(CdmBase
... cdmBaseToUpdate
) {
800 getSession().getTransaction().commit();
801 getSession().clear();
802 getSession().beginTransaction();
803 for (CdmBase cdmBase
: cdmBaseToUpdate
){
804 if (cdmBase
!= null){
805 getSession().update(cdmBase
);
811 public Set
<CdmBase
> setSecundumForSubtreeRelations(TreeIndex subTreeIndex
, Reference newRef
,
812 Set
<UUID
> relationTypes
, boolean overwriteExisting
, boolean includeSharedTaxa
, boolean emptyDetail
, IProgressMonitor monitor
) {
814 String queryStr
= forSubtreeRelationQueryStr(includeSharedTaxa
, overwriteExisting
, subTreeIndex
, SelectMode
.ID
);
816 Set
<CdmBase
> result
= new HashSet
<>();
817 Query query
= getSession().createQuery(queryStr
);
818 @SuppressWarnings("unchecked")
819 List
<List
<Integer
>> partitionList
= splitIdList(query
.list(), DEFAULT_SET_SUBTREE_PARTITION_SIZE
);
820 for (List
<Integer
> relIdList
: partitionList
){
821 List
<TaxonRelationship
> relList
= taxonRelDao
.loadList(relIdList
, null, null);
822 for (TaxonRelationship rel
: relList
){
824 rel
= CdmBase
.deproxy(rel
);
826 NamedSource sourceBefore
= rel
.getSource();
827 Reference refBefore
= rel
.getCitation();
828 String refDetailBefore
= rel
.getCitationMicroReference();
829 if (newRef
== null && rel
.getCitation() !=null
830 || newRef
!= null && (rel
.getCitation() == null || !newRef
.equals(rel
.getCitation()) )){
831 rel
.setCitation(newRef
);
834 if (rel
.getCitationMicroReference() != null){
835 rel
.setCitationMicroReference(null);
838 //compute updated objects
839 NamedSource sourceAfter
= rel
.getSource();
840 if (!CdmUtils
.nullSafeEqual(sourceBefore
, sourceAfter
)){
842 }else if (sourceBefore
!= null && sourceBefore
.equals(sourceAfter
)
843 && (!CdmUtils
.nullSafeEqual(refBefore
, sourceAfter
.getCitation())
844 || !CdmUtils
.nullSafeEqual(refDetailBefore
,sourceAfter
.getCitationMicroReference()))
846 result
.add(sourceBefore
);
850 if (monitor
.isCanceled()){
855 commitAndRestartTransaction();
856 monitor
.worked(relList
.size());
862 private List
<List
<Integer
>> splitIdList(List
<Integer
> idList
, Integer size
){
863 List
<List
<Integer
>> result
= new ArrayList
<>();
864 for (int i
= 0; (i
*size
)<idList
.size(); i
++) {
865 int upper
= Math
.min((i
+1)*size
, idList
.size());
866 result
.add(idList
.subList(i
*size
, upper
));
872 public int countPublishForSubtreeAcceptedTaxa(TreeIndex subTreeIndex
, boolean publish
, boolean includeSharedTaxa
, boolean includeHybrids
) {
873 String queryStr
= forSubtreeAcceptedQueryStr(includeSharedTaxa
, subTreeIndex
, !includeHybrids
, SelectMode
.COUNT
);
874 queryStr
+= " AND t.publish != :publish ";
875 System
.out
.println(queryStr
);
876 Query query
= getSession().createQuery(queryStr
);
877 query
.setBoolean("publish", publish
);
878 return ((Long
)query
.uniqueResult()).intValue();
882 public int countPublishForSubtreeSynonyms(TreeIndex subTreeIndex
, boolean publish
, boolean includeSharedTaxa
, boolean includeHybrids
) {
883 String queryStr
= forSubtreeSynonymQueryStr(includeSharedTaxa
, subTreeIndex
, !includeHybrids
, SelectMode
.COUNT
);
884 queryStr
+= " AND syn.publish != :publish ";
885 Query query
= getSession().createQuery(queryStr
);
886 query
.setBoolean("publish", publish
);
887 return ((Long
)query
.uniqueResult()).intValue();
891 public Set
<TaxonBase
> setPublishForSubtreeAcceptedTaxa(TreeIndex subTreeIndex
, boolean publish
,
892 boolean includeSharedTaxa
, boolean includeHybrids
, IProgressMonitor monitor
) {
893 String queryStr
= forSubtreeAcceptedQueryStr(includeSharedTaxa
, subTreeIndex
, !includeHybrids
, SelectMode
.ID
);
894 queryStr
+= " AND t.publish != :publish ";
895 return setPublish(publish
, queryStr
, null, monitor
);
899 public Set
<TaxonBase
> setPublishForSubtreeSynonyms(TreeIndex subTreeIndex
, boolean publish
,
900 boolean includeSharedTaxa
, boolean includeHybrids
, IProgressMonitor monitor
) {
901 String queryStr
= forSubtreeSynonymQueryStr(includeSharedTaxa
, subTreeIndex
, !includeHybrids
, SelectMode
.ID
);
902 queryStr
+= " AND syn.publish != :publish ";
903 return setPublish(publish
, queryStr
, null, monitor
);
907 public int countPublishForSubtreeRelatedTaxa(TreeIndex subTreeIndex
, boolean publish
, boolean includeSharedTaxa
, boolean includeHybrids
) {
908 String queryStr
= forSubtreeRelatedTaxaQueryStr(includeSharedTaxa
, subTreeIndex
, !includeHybrids
, SelectMode
.COUNT
);
909 queryStr
+= " AND relTax.publish != :publish ";
910 Query query
= getSession().createQuery(queryStr
);
911 query
.setBoolean("publish", publish
);
912 return ((Long
)query
.uniqueResult()).intValue();
916 public Set
<TaxonBase
> setPublishForSubtreeRelatedTaxa(TreeIndex subTreeIndex
, boolean publish
,
917 Set
<UUID
> relationTypes
, boolean includeSharedTaxa
, boolean includeHybrids
,
918 IProgressMonitor monitor
) {
919 String queryStr
= forSubtreeRelatedTaxaQueryStr(includeSharedTaxa
, subTreeIndex
, !includeHybrids
, SelectMode
.ID
);
920 queryStr
+= " AND relTax.publish != :publish ";
921 queryStr
+= " AND rel.type.uuid IN (:relTypeUuid)";
922 return setPublish(publish
, queryStr
, relationTypes
, monitor
);
925 private <T
extends TaxonBase
<?
>> Set
<T
> setPublish(boolean publish
, String queryStr
, Set
<UUID
> relTypeUuids
, IProgressMonitor monitor
) {
926 Set
<T
> result
= new HashSet
<>();
927 Query query
= getSession().createQuery(queryStr
);
928 query
.setBoolean("publish", publish
);
929 if (relTypeUuids
!= null && !relTypeUuids
.isEmpty()){
930 query
.setParameterList("relTypeUuid", relTypeUuids
);
932 @SuppressWarnings("unchecked")
933 List
<List
<Integer
>> partitionList
= splitIdList(query
.list(), DEFAULT_SET_SUBTREE_PARTITION_SIZE
);
934 for (List
<Integer
> taxonIdList
: partitionList
){
935 @SuppressWarnings({ "unchecked", "rawtypes" })
936 List
<T
> taxonList
= (List
)taxonDao
.loadList(taxonIdList
, null, null);
937 for (T taxonBase
: taxonList
){
938 if (taxonBase
!= null){
939 if (taxonBase
.isPublish() != publish
){ //to be on the save side
940 taxonBase
.setPublish(publish
);
941 result
.add(CdmBase
.deproxy(taxonBase
));
944 if (monitor
.isCanceled()){
949 commitAndRestartTransaction();
954 private String
forSubtreeSynonymQueryStr(boolean includeSharedTaxa
, TreeIndex subTreeIndex
, boolean excludeHybrids
, SelectMode mode
) {
955 String queryStr
= "SELECT " + mode
.hql("syn")
956 + " FROM TaxonNode tn "
957 + " JOIN tn.taxon t "
958 + " JOIN t.synonyms syn "
959 + " LEFT JOIN syn.name n "
960 + " LEFT JOIN syn.secSource ss ";
961 String whereStr
= " tn.treeIndex LIKE '%1$s%%' ";
962 if (!includeSharedTaxa
){
963 whereStr
+= " AND NOT EXISTS ("
964 + "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";
966 whereStr
= handleExcludeHybrids(whereStr
, excludeHybrids
, "syn");
967 queryStr
+= " WHERE " + String
.format(whereStr
, subTreeIndex
.toString());
972 private String
handleExcludeHybrids(String whereStr
, boolean excludeHybrids
, String t
) {
975 String hybridWhere
= " AND (n is NULL OR "
976 + " (n.monomHybrid=0 AND n.binomHybrid=0 "
977 + " AND n.trinomHybrid=0 AND n.hybridFormula=0 )) ";
979 whereStr
+= hybridWhere
; //String.format(hybridWhere, t);
984 private String
forSubtreeRelatedTaxaQueryStr(boolean includeSharedTaxa
, TreeIndex subTreeIndex
,
985 boolean excludeHybrids
, SelectMode mode
) {
986 String queryStr
= "SELECT " + mode
.hql("relTax")
987 + " FROM TaxonNode tn "
988 + " JOIN tn.taxon t "
989 + " JOIN t.relationsToThisTaxon rel"
990 + " JOIN rel.relatedFrom relTax "
991 + " LEFT JOIN relTax.name n ";
992 String whereStr
=" tn.treeIndex LIKE '%1$s%%' ";
993 if (!includeSharedTaxa
){
994 //toTaxon should only be used in the given subtree
995 whereStr
+= " AND NOT EXISTS ("
996 + "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";
997 //from taxon should not be used in another classification
998 whereStr
+= " AND NOT EXISTS ("
999 + "FROM TaxonNode tn3 WHERE tn3.taxon = relTax AND tn3.treeIndex not like '%1$s%%') ";
1000 //fromTaxon should not be related as e.g. pro parte synonym or misapplication to
1001 //another taxon which is not part of the subtree
1002 //TODO and has not the publish state
1003 whereStr
+= " AND NOT EXISTS ("
1004 + "FROM TaxonNode tn4 JOIN tn4.taxon t2 JOIN t2.relationsToThisTaxon rel2 "
1005 + " WHERE rel2.relatedFrom = relTax AND tn4.treeIndex not like '%1$s%%' "
1006 + " AND tn4.taxon.publish != :publish ) ";
1008 whereStr
= handleExcludeHybrids(whereStr
, excludeHybrids
, "relTax");
1009 queryStr
+= " WHERE " + String
.format(whereStr
, subTreeIndex
.toString());
1017 private String
forSubtreeRelationQueryStr(boolean includeSharedTaxa
, boolean overwriteExisting
,
1018 TreeIndex subTreeIndex
, SelectMode mode
) {
1020 String queryStr
= "SELECT " + mode
.hql("rel")
1021 + " FROM TaxonNode tn "
1022 + " JOIN tn.taxon t "
1023 + " JOIN t.relationsToThisTaxon rel "
1024 + " LEFT JOIN rel.source src ";
1025 String whereStr
=" tn.treeIndex LIKE '%1$s%%' ";
1026 if (!includeSharedTaxa
){
1027 //toTaxon should only be used in the given subtree
1028 whereStr
+= " AND NOT EXISTS ("
1029 + "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";
1031 queryStr
+= " WHERE " + String
.format(whereStr
, subTreeIndex
.toString());
1032 if (!overwriteExisting
){
1033 queryStr
+= " AND (rel.source IS NULL OR src.citation IS NULL) ";
1039 private enum SelectMode
{
1040 COUNT(" count(*) "),
1045 SelectMode(String hql
){
1048 public String
hql(String prefix
){
1052 return CdmUtils
.Nz(prefix
)+"." + hql
;
1054 return CdmUtils
.Nz(prefix
) + hql
;
1056 default: return hql
;
1062 private String
forSubtreeAcceptedQueryStr(boolean includeSharedTaxa
, TreeIndex subTreeIndex
, boolean excludeHybrids
, SelectMode mode
) {
1063 String queryStr
= "SELECT " + mode
.hql("t")
1064 + " FROM TaxonNode tn "
1065 + " JOIN tn.taxon t "
1066 + " LEFT JOIN t.name n "
1067 + " LEFT JOIN t.secSource ss ";
1068 String whereStr
= " tn.treeIndex like '%1$s%%' ";
1069 if (!includeSharedTaxa
){
1070 whereStr
+= " AND NOT EXISTS ("
1071 + "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";
1073 whereStr
= handleExcludeHybrids(whereStr
, excludeHybrids
, "t");
1074 queryStr
+= " WHERE " + String
.format(whereStr
, subTreeIndex
.toString());
1080 public List
<UuidAndTitleCache
<TaxonNode
>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification
, Integer limit
, String pattern
, boolean searchForClassifications
, boolean includeDoubtful
) {
1082 Query query
= createQueryForUuidAndTitleCache(limit
, classification
.getUuid(), pattern
, includeDoubtful
);
1083 @SuppressWarnings("unchecked")
1084 List
<SortableTaxonNodeQueryResult
> result
= query
.list();
1087 if (searchForClassifications
){
1088 String queryString
= "SELECT new " + SortableTaxonNodeQueryResult
.class.getName() + "("
1089 + " node.uuid, node.id, node.classification.titleCache"
1091 + " FROM TaxonNode AS node "
1092 + " WHERE node.classification.id = " + classification
.getId() +
1093 " AND node.taxon IS NULL";
1094 if (pattern
!= null){
1095 if (pattern
.equals("?")){
1098 if (!pattern
.endsWith("*")){
1101 pattern
= pattern
.replace("*", "%");
1102 pattern
= pattern
.replace("?", "%");
1103 queryString
= queryString
+ " AND node.classification.titleCache LIKE (:pattern) " ;
1106 query
= getSession().createQuery(queryString
);
1109 query
.setMaxResults(limit
);
1112 if (pattern
!= null && !pattern
.equals("?")){
1113 query
.setParameter("pattern", pattern
);
1115 @SuppressWarnings("unchecked")
1116 List
<SortableTaxonNodeQueryResult
> resultClassifications
= query
.list();
1118 result
.addAll(resultClassifications
);
1121 if(result
.size() == 0){
1124 List
<UuidAndTitleCache
<TaxonNode
>> list
= new ArrayList
<>(result
.size());
1125 Collections
.sort(result
, new SortableTaxonNodeQueryResultComparator());
1126 for (SortableTaxonNodeQueryResult resultDTO
: result
){
1127 list
.add(new UuidAndTitleCache
<>(TaxonNode
.class, resultDTO
.getTaxonNodeUuid(), resultDTO
.getTaxonNodeId(), resultDTO
.getTaxonTitleCache()));
1135 public List
<TaxonNodeDto
> getTaxonNodeDto(Integer limit
, String pattern
, UUID classificationUuid
) {
1136 String queryString
= "SELECT new " + SortableTaxonNodeQueryResult
.class.getName() + "("
1137 + "tn.uuid, tn.id, t.titleCache, rank "
1139 + " FROM TaxonNode tn "
1140 + " INNER JOIN tn.taxon AS t "
1141 + " INNER JOIN tn.classification AS cls "
1142 + " INNER JOIN t.name AS name "
1143 + " LEFT OUTER JOIN name.rank AS rank "
1144 + " WHERE t.titleCache LIKE :pattern ";
1145 if(classificationUuid
!= null){
1146 queryString
+= "AND cls.uuid = :classificationUuid";
1149 Query query
= getSession().createQuery(queryString
);
1151 query
.setParameter("pattern", pattern
.toLowerCase()+"%");
1152 if(classificationUuid
!= null){
1153 query
.setParameter("classificationUuid", classificationUuid
);
1156 @SuppressWarnings("unchecked")
1157 List
<SortableTaxonNodeQueryResult
> result
= query
.list();
1158 Collections
.sort(result
, new SortableTaxonNodeQueryResultComparator());
1160 List
<TaxonNodeDto
> list
= new ArrayList
<>();
1161 for(SortableTaxonNodeQueryResult queryDTO
: result
){
1162 list
.add(new TaxonNodeDto(queryDTO
.getTaxonNodeUuid(), queryDTO
.getTaxonNodeId(), queryDTO
.getTaxonTitleCache()));
1168 public List
<TaxonNodeDto
> getUuidAndTitleCache(Integer limit
, String pattern
, UUID classificationUuid
) {
1169 return getUuidAndTitleCache(limit
, pattern
, classificationUuid
, false);
1173 public List
<UuidAndTitleCache
<TaxonNode
>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1174 Classification classification
, Integer limit
, String pattern
, boolean searchForClassifications
) {
1175 return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification
, limit
, pattern
, searchForClassifications
, false);