1
|
/**
|
2
|
* Copyright (C) 2007 EDIT
|
3
|
* European Distributed Institute of Taxonomy
|
4
|
* http://www.e-taxonomy.eu
|
5
|
*
|
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.
|
8
|
*/
|
9
|
|
10
|
package eu.etaxonomy.cdm.persistence.dao.hibernate.taxon;
|
11
|
|
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;
|
21
|
import java.util.Map;
|
22
|
import java.util.Set;
|
23
|
import java.util.UUID;
|
24
|
|
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;
|
34
|
|
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.Reference;
|
43
|
import eu.etaxonomy.cdm.model.taxon.Classification;
|
44
|
import eu.etaxonomy.cdm.model.taxon.Synonym;
|
45
|
import eu.etaxonomy.cdm.model.taxon.Taxon;
|
46
|
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
|
47
|
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
|
48
|
import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
|
49
|
import eu.etaxonomy.cdm.persistence.dao.common.Restriction;
|
50
|
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.AnnotatableDaoImpl;
|
51
|
import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;
|
52
|
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
|
53
|
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
|
54
|
import eu.etaxonomy.cdm.persistence.dto.SortableTaxonNodeQueryResult;
|
55
|
import eu.etaxonomy.cdm.persistence.dto.SortableTaxonNodeQueryResultComparator;
|
56
|
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
|
57
|
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
|
58
|
import eu.etaxonomy.cdm.persistence.query.OrderHint;
|
59
|
|
60
|
/**
|
61
|
* @author a.mueller
|
62
|
* @since 16.06.2009
|
63
|
*/
|
64
|
@Repository
|
65
|
@Qualifier("taxonNodeDaoHibernateImpl")
|
66
|
public class TaxonNodeDaoHibernateImpl extends AnnotatableDaoImpl<TaxonNode>
|
67
|
implements ITaxonNodeDao {
|
68
|
|
69
|
private static final Logger logger = Logger.getLogger(TaxonNodeDaoHibernateImpl.class);
|
70
|
|
71
|
@Autowired
|
72
|
private ITaxonDao taxonDao;
|
73
|
@Autowired
|
74
|
private IClassificationDao classificationDao;
|
75
|
|
76
|
public TaxonNodeDaoHibernateImpl() {
|
77
|
super(TaxonNode.class);
|
78
|
}
|
79
|
|
80
|
@Override
|
81
|
public UUID delete(TaxonNode persistentObject, boolean deleteChildren){
|
82
|
Taxon taxon = persistentObject.getTaxon();
|
83
|
taxon = HibernateProxyHelper.deproxy(taxon);
|
84
|
|
85
|
/*Session session = this.getSession();
|
86
|
Query query = session.createQuery("from TaxonNode t where t.taxon = :taxon");
|
87
|
query.setParameter("taxon", taxon);
|
88
|
List result = query.list();*/
|
89
|
if (taxon != null){
|
90
|
Hibernate.initialize(taxon);
|
91
|
Hibernate.initialize(taxon.getTaxonNodes());
|
92
|
Set<TaxonNode> nodes = taxon.getTaxonNodes();
|
93
|
//Hibernate.initialize(taxon.getTaxonNodes());
|
94
|
for (TaxonNode node:nodes) {
|
95
|
node = HibernateProxyHelper.deproxy(node);
|
96
|
|
97
|
if (node.equals(persistentObject)){
|
98
|
if (node.hasChildNodes()){
|
99
|
Iterator<TaxonNode> childNodes = node.getChildNodes().iterator();
|
100
|
TaxonNode childNode;
|
101
|
List<TaxonNode> listForDeletion = new ArrayList<>();
|
102
|
while (childNodes.hasNext()){
|
103
|
childNode = childNodes.next();
|
104
|
listForDeletion.add(childNode);
|
105
|
childNodes.remove();
|
106
|
|
107
|
}
|
108
|
for (TaxonNode deleteNode:listForDeletion){
|
109
|
delete(deleteNode, deleteChildren);
|
110
|
}
|
111
|
}
|
112
|
|
113
|
taxon.removeTaxonNode(node, deleteChildren);
|
114
|
taxonDao.saveOrUpdate(taxon);
|
115
|
taxon = HibernateProxyHelper.deproxy(taxonDao.findByUuid(taxon.getUuid()), Taxon.class);
|
116
|
taxonDao.delete(taxon);
|
117
|
|
118
|
}
|
119
|
}
|
120
|
}
|
121
|
|
122
|
UUID result = super.delete(persistentObject);
|
123
|
return result;
|
124
|
}
|
125
|
|
126
|
@Override
|
127
|
public List<TaxonNode> getTaxonOfAcceptedTaxaByClassification(Classification classification, Integer start, Integer end) {
|
128
|
int classificationId = classification.getId();
|
129
|
String limit = "";
|
130
|
if(start !=null && end != null){
|
131
|
limit = "LIMIT "+start+"," +end;
|
132
|
}
|
133
|
//FIXME write test
|
134
|
String queryString = "SELECT DISTINCT nodes.*,taxa.titleCache "
|
135
|
+ " FROM TaxonNode AS nodes "
|
136
|
+ " LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id "
|
137
|
+ " WHERE taxa.DTYPE = 'Taxon' "
|
138
|
+ " AND nodes.classification_id = " + classificationId +
|
139
|
" ORDER BY taxa.titleCache " + limit;
|
140
|
@SuppressWarnings("unchecked")
|
141
|
List<TaxonNode> result = getSession().createSQLQuery(queryString).addEntity(TaxonNode.class).list();
|
142
|
|
143
|
return result;
|
144
|
}
|
145
|
|
146
|
@Override
|
147
|
public int countTaxonOfAcceptedTaxaByClassification(Classification classification){
|
148
|
int classificationId = classification.getId();
|
149
|
//FIXME write test
|
150
|
String queryString = ""
|
151
|
+ " SELECT DISTINCT COUNT('nodes.*') "
|
152
|
+ " FROM TaxonNode AS nodes "
|
153
|
+ " LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id "
|
154
|
+ " WHERE taxa.DTYPE = 'Taxon' AND nodes.classification_id = " + classificationId;
|
155
|
@SuppressWarnings("unchecked")
|
156
|
List<BigInteger> result = getSession().createSQLQuery(queryString).list();
|
157
|
return result.get(0).intValue ();
|
158
|
}
|
159
|
|
160
|
@Override
|
161
|
public List<TaxonNodeDto> listChildNodesAsUuidAndTitleCache(TaxonNodeDto parent) {
|
162
|
String queryString =
|
163
|
" SELECT tn.uuid, tn.id, t.titleCache "
|
164
|
+ " FROM TaxonNode tn "
|
165
|
+ " INNER JOIN tn.taxon AS t "
|
166
|
+ " WHERE tn.parent.uuid = :parentId";
|
167
|
|
168
|
Query query = getSession().createQuery(queryString);
|
169
|
query.setParameter("parentId", parent.getUuid());
|
170
|
|
171
|
@SuppressWarnings("unchecked")
|
172
|
List<Object[]> result = query.list();
|
173
|
|
174
|
List<TaxonNodeDto> list = new ArrayList<>();
|
175
|
for(Object[] object : result){
|
176
|
list.add(new TaxonNodeDto((UUID) object[0],(Integer) object[1], (String) object[2]));
|
177
|
}
|
178
|
return list;
|
179
|
}
|
180
|
|
181
|
@Override
|
182
|
public List<TaxonNodeDto> listChildNodesAsTaxonNodeDto(TaxonNodeDto parent) {
|
183
|
String queryString =
|
184
|
" SELECT tn "
|
185
|
+ " FROM TaxonNode tn "
|
186
|
+ " INNER JOIN tn.taxon AS t "
|
187
|
+ " WHERE tn.parent.uuid = :parentId";
|
188
|
Query query = getSession().createQuery(queryString);
|
189
|
query.setParameter("parentId", parent.getUuid());
|
190
|
|
191
|
@SuppressWarnings("unchecked")
|
192
|
List<TaxonNode> result = query.list();
|
193
|
|
194
|
List<TaxonNodeDto> list = new ArrayList<>();
|
195
|
for(TaxonNode object : result){
|
196
|
list.add(new TaxonNodeDto(object));
|
197
|
}
|
198
|
return list;
|
199
|
}
|
200
|
|
201
|
@Override
|
202
|
public List<TaxonNodeDto> getUuidAndTitleCache(Integer limit, String pattern, UUID classificationUuid, boolean includeDoubtful) {
|
203
|
|
204
|
Query query = createQueryForUuidAndTitleCache(limit, classificationUuid, pattern, includeDoubtful);
|
205
|
@SuppressWarnings("unchecked")
|
206
|
List<SortableTaxonNodeQueryResult> result = query.list();
|
207
|
Collections.sort(result, new SortableTaxonNodeQueryResultComparator());
|
208
|
if(logger.isTraceEnabled()){
|
209
|
logger.trace("number of matches:" + result.size());
|
210
|
result.stream().forEach(o -> logger.trace("uuid: " + o.getTaxonNodeUuid() + " titleCache:" + o.getTaxonTitleCache() + " rank: " + o.getNameRank()));
|
211
|
}
|
212
|
List<TaxonNodeDto> list = new ArrayList<>();
|
213
|
// int index = limit;
|
214
|
for(SortableTaxonNodeQueryResult stnqr : result){
|
215
|
// if (index > 0){
|
216
|
list.add(new TaxonNodeDto(stnqr.getTaxonNodeUuid(),stnqr.getTaxonNodeId(), stnqr.getTaxonTitleCache()));
|
217
|
// index --;
|
218
|
// }
|
219
|
|
220
|
}
|
221
|
|
222
|
return list;
|
223
|
}
|
224
|
|
225
|
private Query createQueryForUuidAndTitleCache(Integer limit, UUID classificationUuid, String pattern, boolean includeDoubtful){
|
226
|
String doubtfulPattern = "";
|
227
|
String queryString = "SELECT new " + SortableTaxonNodeQueryResult.class.getName() + "("
|
228
|
+ " node.uuid, node.id, t.titleCache, rank"
|
229
|
+ ") "
|
230
|
+ " FROM TaxonNode AS node "
|
231
|
+ " JOIN node.taxon as t " // FIXME why not inner join here?
|
232
|
+ " INNER JOIN t.name AS name "
|
233
|
+ " LEFT OUTER JOIN name.rank AS rank "
|
234
|
+ " WHERE ";
|
235
|
|
236
|
if (classificationUuid != null){
|
237
|
queryString = queryString + " node.classification.uuid like :classificationUuid " ;
|
238
|
}
|
239
|
if (pattern != null){
|
240
|
if (pattern.equals("?")){
|
241
|
limit = null;
|
242
|
} else{
|
243
|
if (!pattern.endsWith("*")){
|
244
|
pattern += "%";
|
245
|
}
|
246
|
pattern = pattern.replace("*", "%");
|
247
|
pattern = pattern.replace("?", "%");
|
248
|
if (classificationUuid != null){
|
249
|
queryString = queryString + " AND ";
|
250
|
}
|
251
|
queryString = queryString + " (t.titleCache LIKE (:pattern) " ;
|
252
|
doubtfulPattern = "?" + pattern;
|
253
|
if (includeDoubtful){
|
254
|
queryString = queryString + " OR t.titleCache LIKE (:doubtfulPattern))";
|
255
|
}else{
|
256
|
queryString = queryString + ")";
|
257
|
}
|
258
|
}
|
259
|
|
260
|
}
|
261
|
|
262
|
Query query = getSession().createQuery(queryString);
|
263
|
if (pattern != null){
|
264
|
query.setParameter("pattern", pattern);
|
265
|
}
|
266
|
if (includeDoubtful){
|
267
|
query.setParameter("doubtfulPattern", doubtfulPattern);
|
268
|
}
|
269
|
|
270
|
if(classificationUuid != null){
|
271
|
query.setParameter("classificationUuid", classificationUuid);
|
272
|
}
|
273
|
if (limit != null){
|
274
|
query.setMaxResults(limit);
|
275
|
}
|
276
|
return query;
|
277
|
}
|
278
|
|
279
|
|
280
|
|
281
|
@Override
|
282
|
public TaxonNodeDto getParentUuidAndTitleCache(TaxonNodeDto child) {
|
283
|
String queryString = ""
|
284
|
+ " SELECT tn.parent.uuid, tn.parent.id, tn.parent.taxon.titleCache, "
|
285
|
+ " tn.parent.classification.titleCache "
|
286
|
+ " FROM TaxonNode tn"
|
287
|
+ " LEFT OUTER JOIN tn.parent.taxon"
|
288
|
+ " WHERE tn.id = :childId";
|
289
|
Query query = getSession().createQuery(queryString);
|
290
|
query.setParameter("childId", child.getId());
|
291
|
List<TaxonNodeDto> list = new ArrayList<>();
|
292
|
|
293
|
@SuppressWarnings("unchecked")
|
294
|
List<Object[]> result = query.list();
|
295
|
|
296
|
for(Object[] object : result){
|
297
|
UUID uuid = (UUID) object[0];
|
298
|
Integer id = (Integer) object[1];
|
299
|
String taxonTitleCache = (String) object[2];
|
300
|
String classificationTitleCache = (String) object[3];
|
301
|
if(taxonTitleCache!=null){
|
302
|
list.add(new TaxonNodeDto(uuid,id, taxonTitleCache));
|
303
|
}
|
304
|
else{
|
305
|
list.add(new TaxonNodeDto(uuid,id, classificationTitleCache));
|
306
|
}
|
307
|
}
|
308
|
if(list.size()==1){
|
309
|
return list.iterator().next();
|
310
|
}
|
311
|
return null;
|
312
|
}
|
313
|
@Override
|
314
|
public List<TaxonNode> listChildrenOf(TaxonNode node, Integer pageSize, Integer pageIndex,
|
315
|
boolean recursive, boolean includeUnpublished, List<String> propertyPaths, Comparator<TaxonNode> comparator){
|
316
|
return listChildrenOfRecursive(node,new ArrayList<>(), pageSize, pageIndex, recursive, includeUnpublished, propertyPaths, comparator);
|
317
|
}
|
318
|
|
319
|
private List<TaxonNode> listChildrenOfRecursive(TaxonNode node, List<TaxonNode> previousResult, Integer pageSize, Integer pageIndex,
|
320
|
boolean recursive, boolean includeUnpublished, List<String> propertyPaths, Comparator<TaxonNode> comparator){
|
321
|
|
322
|
if (!previousResult.contains(node)){
|
323
|
previousResult.add(node);
|
324
|
}
|
325
|
if (recursive == true && comparator == null ){
|
326
|
Criteria crit = childrenOfCriteria(node, includeUnpublished);
|
327
|
|
328
|
this.addPageSizeAndNumber(crit, pageSize, pageIndex);
|
329
|
@SuppressWarnings("unchecked")
|
330
|
List<TaxonNode> results = crit.list();
|
331
|
results.remove(node);
|
332
|
defaultBeanInitializer.initializeAll(results, propertyPaths);
|
333
|
return results;
|
334
|
|
335
|
} else if (recursive == true){
|
336
|
List<TaxonNode> children = node.getChildNodes();
|
337
|
Collections.sort(children, comparator);
|
338
|
for (TaxonNode child: children){
|
339
|
if (!previousResult.contains(child)){
|
340
|
previousResult.add(child);
|
341
|
}
|
342
|
if (child.hasChildNodes()){
|
343
|
previousResult = listChildrenOfRecursive(child, previousResult, pageSize, pageIndex,
|
344
|
recursive, includeUnpublished, propertyPaths,comparator);
|
345
|
}
|
346
|
}
|
347
|
return previousResult;
|
348
|
|
349
|
} else{
|
350
|
return classificationDao.listChildrenOf(node.getTaxon(), node.getClassification(), null,
|
351
|
includeUnpublished, pageSize, pageIndex, propertyPaths);
|
352
|
}
|
353
|
}
|
354
|
|
355
|
@Override
|
356
|
public Long countChildrenOf(TaxonNode node, Classification classification,
|
357
|
boolean recursive, boolean includeUnpublished) {
|
358
|
|
359
|
if (recursive == true){
|
360
|
Criteria crit = childrenOfCriteria(node, includeUnpublished);
|
361
|
crit.setProjection(Projections.rowCount());
|
362
|
return ((Integer)crit.uniqueResult().hashCode()).longValue();
|
363
|
}else{
|
364
|
return classificationDao.countChildrenOf(
|
365
|
node.getTaxon(), classification, null, includeUnpublished);
|
366
|
}
|
367
|
}
|
368
|
|
369
|
private Criteria childrenOfCriteria(TaxonNode node, boolean includeUnpublished) {
|
370
|
Criteria crit = getSession().createCriteria(TaxonNode.class);
|
371
|
crit.add( Restrictions.like("treeIndex", node.treeIndex()+ "%") );
|
372
|
if (!includeUnpublished){
|
373
|
crit.createCriteria("taxon").add( Restrictions.eq("publish", Boolean.TRUE));
|
374
|
}
|
375
|
return crit;
|
376
|
}
|
377
|
|
378
|
@Override
|
379
|
public List<TaxonNodeAgentRelation> listTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,
|
380
|
UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer start, Integer limit,
|
381
|
List<String> propertyPaths) {
|
382
|
|
383
|
StringBuilder hql = prepareListTaxonNodeAgentRelations(taxonUuid, classificationUuid,
|
384
|
agentUuid, rankUuid, relTypeUuid, false);
|
385
|
|
386
|
Query query = getSession().createQuery(hql.toString());
|
387
|
|
388
|
if(limit != null) {
|
389
|
query.setMaxResults(limit);
|
390
|
if(start != null) {
|
391
|
query.setFirstResult(start);
|
392
|
}
|
393
|
}
|
394
|
|
395
|
setParamsForListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, query);
|
396
|
|
397
|
@SuppressWarnings("unchecked")
|
398
|
List<TaxonNodeAgentRelation> records = query.list();
|
399
|
|
400
|
if(propertyPaths != null) {
|
401
|
defaultBeanInitializer.initializeAll(records, propertyPaths);
|
402
|
}
|
403
|
return records;
|
404
|
}
|
405
|
|
406
|
@Override
|
407
|
public <S extends TaxonNode> List<S> list(Class<S> type, List<Restriction<?>> restrictions, Integer limit,
|
408
|
Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
|
409
|
// TODO Auto-generated method stub
|
410
|
return list(type, restrictions, limit, start, orderHints, propertyPaths, INCLUDE_UNPUBLISHED);
|
411
|
}
|
412
|
|
413
|
@Override
|
414
|
public <S extends TaxonNode> List<S> list(Class<S> type, List<Restriction<?>> restrictions, Integer limit,
|
415
|
Integer start, List<OrderHint> orderHints, List<String> propertyPaths, boolean includePublished) {
|
416
|
|
417
|
Criteria criteria = createCriteria(type, restrictions, false);
|
418
|
|
419
|
if(!includePublished){
|
420
|
criteria.add(Restrictions.eq("taxon.publish", true));
|
421
|
}
|
422
|
|
423
|
addLimitAndStart(criteria, limit, start);
|
424
|
addOrder(criteria, orderHints);
|
425
|
|
426
|
@SuppressWarnings("unchecked")
|
427
|
List<S> result = criteria.list();
|
428
|
defaultBeanInitializer.initializeAll(result, propertyPaths);
|
429
|
return result;
|
430
|
}
|
431
|
|
432
|
@Override
|
433
|
public long count(Class<? extends TaxonNode> type, List<Restriction<?>> restrictions) {
|
434
|
return count(type, restrictions, INCLUDE_UNPUBLISHED);
|
435
|
}
|
436
|
|
437
|
|
438
|
@Override
|
439
|
public long count(Class<? extends TaxonNode> type, List<Restriction<?>> restrictions, boolean includePublished) {
|
440
|
|
441
|
Criteria criteria = createCriteria(type, restrictions, false);
|
442
|
if(!includePublished){
|
443
|
criteria.add(Restrictions.eq("taxon.publish", true));
|
444
|
}
|
445
|
criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
|
446
|
return (Long) criteria.uniqueResult();
|
447
|
}
|
448
|
|
449
|
@Override
|
450
|
public long countTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid, UUID rankUuid, UUID relTypeUuid) {
|
451
|
|
452
|
StringBuilder hql = prepareListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, true);
|
453
|
Query query = getSession().createQuery(hql.toString());
|
454
|
|
455
|
setParamsForListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, query);
|
456
|
|
457
|
Long count = Long.parseLong(query.uniqueResult().toString());
|
458
|
|
459
|
return count;
|
460
|
}
|
461
|
|
462
|
/**
|
463
|
* @param taxonUuid
|
464
|
* @param classificationUuid
|
465
|
* @param agentUuid
|
466
|
* @param relTypeUuid TODO
|
467
|
* @param doCount TODO
|
468
|
* @param rankId
|
469
|
* limit to taxa having this rank, only applies if <code>taxonUuid = null</code>
|
470
|
* @return
|
471
|
*/
|
472
|
private StringBuilder prepareListTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid, UUID rankUuid, UUID relTypeUuid, boolean doCount) {
|
473
|
|
474
|
StringBuilder hql = new StringBuilder();
|
475
|
|
476
|
String join_fetch_mode = doCount ? "JOIN" : "JOIN FETCH";
|
477
|
|
478
|
if(doCount) {
|
479
|
hql.append("SELECT COUNT(tnar)");
|
480
|
} else {
|
481
|
hql.append("SELECT tnar");
|
482
|
}
|
483
|
|
484
|
hql.append(" FROM TaxonNodeAgentRelation AS tnar ");
|
485
|
if(taxonUuid != null) {
|
486
|
// taxonUuid is search filter, do not fetch it
|
487
|
hql.append(" JOIN tnar.taxonNode AS tn "
|
488
|
+ " JOIN tn.taxon AS t ");
|
489
|
} else {
|
490
|
hql.append(join_fetch_mode)
|
491
|
.append(" tnar.taxonNode AS tn ")
|
492
|
.append(join_fetch_mode).append(" tn.taxon AS t ");
|
493
|
if(rankUuid != null) {
|
494
|
hql.append(" join t.name as n ");
|
495
|
}
|
496
|
}
|
497
|
hql.append(" JOIN tn.classification AS c ");
|
498
|
if(agentUuid != null) {
|
499
|
// agentUuid is search filter, do not fetch it
|
500
|
// hql.append(" join tnar.agent as a ");
|
501
|
hql.append(join_fetch_mode).append(" tnar.agent AS a ");
|
502
|
} else {
|
503
|
hql.append(join_fetch_mode).append(" tnar.agent AS a ");
|
504
|
}
|
505
|
|
506
|
hql.append(" WHERE (1 = 1) ");
|
507
|
|
508
|
if(relTypeUuid != null) {
|
509
|
hql.append(" AND tnar.type.uuid = :relTypeUuid ");
|
510
|
}
|
511
|
|
512
|
if(taxonUuid != null) {
|
513
|
hql.append(" AND t.uuid = :taxonUuid ");
|
514
|
} else {
|
515
|
if(rankUuid != null) {
|
516
|
hql.append(" AND n.rank.uuid = :rankUuid ");
|
517
|
}
|
518
|
}
|
519
|
if(classificationUuid != null) {
|
520
|
hql.append(" AND c.uuid = :classificationUuid ");
|
521
|
}
|
522
|
if(agentUuid != null) {
|
523
|
hql.append(" AND a.uuid = :agentUuid ");
|
524
|
}
|
525
|
|
526
|
hql.append(" ORDER BY a.titleCache");
|
527
|
return hql;
|
528
|
}
|
529
|
|
530
|
/**
|
531
|
* @param taxonUuid
|
532
|
* @param classificationUuid
|
533
|
* @param agentUuid
|
534
|
* @param relTypeUuid TODO
|
535
|
* @param query
|
536
|
* @param rankId TODO
|
537
|
*/
|
538
|
private void setParamsForListTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid,
|
539
|
UUID rankUuid, UUID relTypeUuid, Query query) {
|
540
|
|
541
|
if(taxonUuid != null) {
|
542
|
query.setParameter("taxonUuid", taxonUuid);
|
543
|
} else {
|
544
|
if(rankUuid != null) {
|
545
|
query.setParameter("rankUuid", rankUuid);
|
546
|
}
|
547
|
}
|
548
|
if(classificationUuid != null) {
|
549
|
query.setParameter("classificationUuid", classificationUuid);
|
550
|
}
|
551
|
if(agentUuid != null) {
|
552
|
query.setParameter("agentUuid", agentUuid);
|
553
|
}
|
554
|
if(relTypeUuid != null) {
|
555
|
query.setParameter("relTypeUuid", relTypeUuid);
|
556
|
}
|
557
|
}
|
558
|
|
559
|
@Override
|
560
|
public Map<TreeIndex, Integer> rankOrderIndexForTreeIndex(List<TreeIndex> treeIndexes,
|
561
|
Integer minRankOrderIndex,
|
562
|
Integer maxRankOrderIndex) {
|
563
|
|
564
|
Map<TreeIndex, Integer> result = new HashMap<>();
|
565
|
if (treeIndexes == null || treeIndexes.isEmpty()){
|
566
|
return result;
|
567
|
}
|
568
|
|
569
|
String hql = " SELECT tn.treeIndex, r.orderIndex "
|
570
|
+ " FROM TaxonNode tn "
|
571
|
+ " JOIN tn.taxon t "
|
572
|
+ " JOIN t.name n "
|
573
|
+ " JOIN n.rank r "
|
574
|
+ " WHERE tn.treeIndex IN (:treeIndexes) ";
|
575
|
if (minRankOrderIndex != null){
|
576
|
hql += " AND r.orderIndex <= :minOrderIndex";
|
577
|
}
|
578
|
if (maxRankOrderIndex != null){
|
579
|
hql += " AND r.orderIndex >= :maxOrderIndex";
|
580
|
}
|
581
|
|
582
|
Query query = getSession().createQuery(hql);
|
583
|
query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));
|
584
|
if (minRankOrderIndex != null){
|
585
|
query.setParameter("minOrderIndex", minRankOrderIndex);
|
586
|
}
|
587
|
if (maxRankOrderIndex != null){
|
588
|
query.setParameter("maxOrderIndex", maxRankOrderIndex);
|
589
|
}
|
590
|
|
591
|
@SuppressWarnings("unchecked")
|
592
|
List<Object[]> list = query.list();
|
593
|
for (Object[] o : list){
|
594
|
result.put(TreeIndex.NewInstance((String)o[0]), (Integer)o[1]);
|
595
|
}
|
596
|
return result;
|
597
|
}
|
598
|
|
599
|
@Override
|
600
|
public Map<TreeIndex, UuidAndTitleCache<?>> taxonUuidsForTreeIndexes(Collection<TreeIndex> treeIndexes) {
|
601
|
Map<TreeIndex, UuidAndTitleCache<?>> result = new HashMap<>();
|
602
|
if (treeIndexes == null || treeIndexes.isEmpty()){
|
603
|
return result;
|
604
|
}
|
605
|
|
606
|
String hql =
|
607
|
" SELECT tn.treeIndex, t.uuid, tnb.titleCache "
|
608
|
+ " FROM TaxonNode tn JOIN tn.taxon t Join t.name tnb "
|
609
|
+ " WHERE tn.treeIndex IN (:treeIndexes) ";
|
610
|
Query query = getSession().createQuery(hql);
|
611
|
query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));
|
612
|
|
613
|
@SuppressWarnings("unchecked")
|
614
|
List<Object[]> list = query.list();
|
615
|
for (Object[] o : list){
|
616
|
result.put(TreeIndex.NewInstance((String)o[0]), new UuidAndTitleCache<>((UUID)o[1], null, (String)o[2]));
|
617
|
}
|
618
|
return result;
|
619
|
}
|
620
|
|
621
|
@Override
|
622
|
public List<TaxonNodeDto> getParentTaxonNodeDtoForRank(
|
623
|
Classification classification, Rank rank, TaxonBase<?> taxonBase) {
|
624
|
|
625
|
Taxon taxon = null;
|
626
|
if (taxonBase instanceof Taxon) {
|
627
|
taxon = CdmBase.deproxy(taxonBase, Taxon.class);
|
628
|
}else {
|
629
|
taxon = CdmBase.deproxy(((Synonym)taxonBase).getAcceptedTaxon());
|
630
|
}
|
631
|
TaxonNode node = null;
|
632
|
if (taxon != null) {
|
633
|
node = taxon.getTaxonNode(classification);
|
634
|
}
|
635
|
List<TaxonNodeDto> result = new ArrayList<>();
|
636
|
if (node != null) {
|
637
|
String treeIndex = node.treeIndex();
|
638
|
List<Integer> ancestorNodeIds = TreeIndex.NewInstance(treeIndex).parentNodeIds(false);
|
639
|
|
640
|
Criteria nodeCrit = getSession().createCriteria(TaxonNode.class);
|
641
|
Criteria taxonCrit = nodeCrit.createCriteria("taxon");
|
642
|
Criteria nameCrit = taxonCrit.createCriteria("name");
|
643
|
nodeCrit.add(Restrictions.in("id", ancestorNodeIds));
|
644
|
nodeCrit.add(Restrictions.eq("classification", classification));
|
645
|
nameCrit.add(Restrictions.eq("rank", rank));
|
646
|
|
647
|
@SuppressWarnings("unchecked")
|
648
|
List<TaxonNode> list = nodeCrit.list();
|
649
|
for (TaxonNode rankNode : list){
|
650
|
TaxonNodeDto dto = new TaxonNodeDto(rankNode);
|
651
|
result.add(dto);
|
652
|
}
|
653
|
}
|
654
|
return result;
|
655
|
}
|
656
|
|
657
|
|
658
|
@Override
|
659
|
public List<TaxonNodeDto> getParentTaxonNodeDtoForRank(
|
660
|
Classification classification, Rank rank, TaxonName name) {
|
661
|
|
662
|
Set<TaxonBase> taxa = name.getTaxonBases();
|
663
|
List<TaxonNodeDto> result = new ArrayList<>();
|
664
|
for (TaxonBase<?> taxonBase:taxa) {
|
665
|
List<TaxonNodeDto> tmpList = getParentTaxonNodeDtoForRank(classification, rank, taxonBase);
|
666
|
for (TaxonNodeDto tmpDto : tmpList){
|
667
|
boolean exists = false; //an equal method does not yet exist for TaxonNodeDto therefore this workaround
|
668
|
for (TaxonNodeDto dto: result){
|
669
|
if (dto.getTreeIndex().equals(tmpDto.getTreeIndex())){
|
670
|
exists = true;
|
671
|
}
|
672
|
}
|
673
|
if (!exists){
|
674
|
result.add(tmpDto);
|
675
|
}
|
676
|
}
|
677
|
}
|
678
|
return result;
|
679
|
}
|
680
|
|
681
|
@Override
|
682
|
public int countSecundumForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, Reference newSec,
|
683
|
boolean overwriteExisting, boolean includeSharedTaxa, boolean emptySecundumDetail) {
|
684
|
String queryStr = forSubtreeAcceptedQueryStr(includeSharedTaxa, subTreeIndex, false, SelectMode.COUNT);
|
685
|
if (!overwriteExisting){
|
686
|
queryStr += " AND t.secSource.citation IS NULL ";
|
687
|
}
|
688
|
return countResult(queryStr);
|
689
|
}
|
690
|
|
691
|
private int countResult(String queryStr) {
|
692
|
Query query = getSession().createQuery(queryStr);
|
693
|
return ((Long)query.uniqueResult()).intValue();
|
694
|
}
|
695
|
|
696
|
@Override
|
697
|
public int countSecundumForSubtreeSynonyms(TreeIndex subTreeIndex, Reference newSec,
|
698
|
boolean overwriteExisting, boolean includeSharedTaxa, boolean emptySecundumDetail) {
|
699
|
String queryStr = forSubtreeSynonymQueryStr(includeSharedTaxa, subTreeIndex, false, SelectMode.COUNT);
|
700
|
if (!overwriteExisting){
|
701
|
queryStr += " AND syn.secSource.citation IS NULL ";
|
702
|
}
|
703
|
return countResult(queryStr);
|
704
|
}
|
705
|
|
706
|
//#3465
|
707
|
@Override
|
708
|
public Set<TaxonBase> setSecundumForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, Reference newSec,
|
709
|
boolean overwriteExisting, boolean includeSharedTaxa, boolean emptyDetail, IProgressMonitor monitor) {
|
710
|
//for some reason this does not work, maybe because the listeners are not activated,
|
711
|
//but also the first taxon for some reason does not get updated in terms of secundum, but only by the update listener
|
712
|
// String where = "SELECT t.id FROM TaxonNode tn JOIN tn.taxon t " +
|
713
|
// " WHERE tn.treeIndex like '%s%%' ORDER BY t.id";
|
714
|
// where = String.format(where, subTreeIndex.toString());
|
715
|
// Query query1 = getSession().createQuery(where);
|
716
|
// List l = query1.list();
|
717
|
//
|
718
|
// String hql = "UPDATE Taxon SET sec = :newSec, publish=false WHERE id IN (" + where + ")";
|
719
|
// Query query = getSession().createQuery(hql);
|
720
|
// query.setParameter("newSec", newSec);
|
721
|
// int n = query.executeUpdate();
|
722
|
|
723
|
String queryStr = forSubtreeAcceptedQueryStr(includeSharedTaxa, subTreeIndex, false, SelectMode.ID);
|
724
|
if (!overwriteExisting){
|
725
|
queryStr += " AND t.secSource.citation IS NULL ";
|
726
|
}
|
727
|
return setSecundum(newSec, emptyDetail, queryStr, monitor);
|
728
|
|
729
|
}
|
730
|
|
731
|
@Override
|
732
|
public Set<TaxonBase> setSecundumForSubtreeSynonyms(TreeIndex subTreeIndex, Reference newSec,
|
733
|
boolean overwriteExisting, boolean includeSharedTaxa, boolean emptyDetail, IProgressMonitor monitor) {
|
734
|
|
735
|
String queryStr = forSubtreeSynonymQueryStr(includeSharedTaxa, subTreeIndex, false, SelectMode.ID);
|
736
|
if (!overwriteExisting){
|
737
|
queryStr += " AND syn.secSource.citation IS NULL ";
|
738
|
}
|
739
|
return setSecundum(newSec, emptyDetail, queryStr, monitor);
|
740
|
}
|
741
|
|
742
|
@SuppressWarnings("unchecked")
|
743
|
private <T extends TaxonBase<?>> Set<T> setSecundum(Reference newSec, boolean emptyDetail, String queryStr, IProgressMonitor monitor) {
|
744
|
Set<T> result = new HashSet<>();
|
745
|
Query query = getSession().createQuery(queryStr);
|
746
|
List<List<Integer>> partitionList = splitIdList(query.list(), DEFAULT_PARTITION_SIZE);
|
747
|
for (List<Integer> taxonIdList : partitionList){
|
748
|
List<TaxonBase> taxonList = taxonDao.loadList(taxonIdList, null, null);
|
749
|
for (TaxonBase<?> taxonBase : taxonList){
|
750
|
if (taxonBase != null){
|
751
|
taxonBase = taxonDao.load(taxonBase.getUuid());
|
752
|
taxonBase.setSec(newSec);
|
753
|
if (emptyDetail){
|
754
|
taxonBase.setSecMicroReference(null);
|
755
|
}
|
756
|
result.add((T)CdmBase.deproxy(taxonBase));
|
757
|
monitor.worked(1);
|
758
|
if (monitor.isCanceled()){
|
759
|
return result;
|
760
|
}
|
761
|
}
|
762
|
}
|
763
|
}
|
764
|
return result;
|
765
|
}
|
766
|
|
767
|
private List<List<Integer>> splitIdList(List<Integer> idList, Integer size){
|
768
|
List<List<Integer>> result = new ArrayList<>();
|
769
|
for (int i = 0; (i*size)<idList.size(); i++) {
|
770
|
int upper = Math.min((i+1)*size, idList.size());
|
771
|
result.add(idList.subList(i*size, upper));
|
772
|
}
|
773
|
return result;
|
774
|
}
|
775
|
|
776
|
@Override
|
777
|
public int countPublishForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, boolean publish, boolean includeSharedTaxa, boolean includeHybrids) {
|
778
|
String queryStr = forSubtreeAcceptedQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.COUNT);
|
779
|
queryStr += " AND t.publish != :publish ";
|
780
|
System.out.println(queryStr);
|
781
|
Query query = getSession().createQuery(queryStr);
|
782
|
query.setBoolean("publish", publish);
|
783
|
return ((Long)query.uniqueResult()).intValue();
|
784
|
}
|
785
|
|
786
|
@Override
|
787
|
public int countPublishForSubtreeSynonyms(TreeIndex subTreeIndex, boolean publish, boolean includeSharedTaxa, boolean includeHybrids) {
|
788
|
String queryStr = forSubtreeSynonymQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.COUNT);
|
789
|
queryStr += " AND syn.publish != :publish ";
|
790
|
Query query = getSession().createQuery(queryStr);
|
791
|
query.setBoolean("publish", publish);
|
792
|
return ((Long)query.uniqueResult()).intValue();
|
793
|
}
|
794
|
|
795
|
@Override
|
796
|
public Set<TaxonBase> setPublishForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, boolean publish,
|
797
|
boolean includeSharedTaxa, boolean includeHybrids, IProgressMonitor monitor) {
|
798
|
String queryStr = forSubtreeAcceptedQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.ID);
|
799
|
queryStr += " AND t.publish != :publish ";
|
800
|
return setPublish(publish, queryStr, null, monitor);
|
801
|
}
|
802
|
|
803
|
@Override
|
804
|
public Set<TaxonBase> setPublishForSubtreeSynonyms(TreeIndex subTreeIndex, boolean publish,
|
805
|
boolean includeSharedTaxa, boolean includeHybrids, IProgressMonitor monitor) {
|
806
|
String queryStr = forSubtreeSynonymQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.ID);
|
807
|
queryStr += " AND syn.publish != :publish ";
|
808
|
return setPublish(publish, queryStr, null, monitor);
|
809
|
}
|
810
|
|
811
|
@Override
|
812
|
public int countPublishForSubtreeRelatedTaxa(TreeIndex subTreeIndex, boolean publish, boolean includeSharedTaxa, boolean includeHybrids) {
|
813
|
String queryStr = forSubtreeRelatedTaxaQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.COUNT);
|
814
|
queryStr += " AND relTax.publish != :publish ";
|
815
|
Query query = getSession().createQuery(queryStr);
|
816
|
query.setBoolean("publish", publish);
|
817
|
return ((Long)query.uniqueResult()).intValue();
|
818
|
}
|
819
|
|
820
|
@Override
|
821
|
public Set<TaxonBase> setPublishForSubtreeRelatedTaxa(TreeIndex subTreeIndex, boolean publish,
|
822
|
Set<UUID> relationTypes, boolean includeSharedTaxa, boolean includeHybrids,
|
823
|
IProgressMonitor monitor) {
|
824
|
String queryStr = forSubtreeRelatedTaxaQueryStr(includeSharedTaxa, subTreeIndex, !includeHybrids, SelectMode.ID);
|
825
|
queryStr += " AND relTax.publish != :publish ";
|
826
|
queryStr += " AND rel.type.uuid IN (:relTypeUuid)";
|
827
|
return setPublish(publish, queryStr, relationTypes, monitor);
|
828
|
}
|
829
|
|
830
|
private static final int DEFAULT_PARTITION_SIZE = 100;
|
831
|
|
832
|
private <T extends TaxonBase<?>> Set<T> setPublish(boolean publish, String queryStr, Set<UUID> relTypeUuids, IProgressMonitor monitor) {
|
833
|
Set<T> result = new HashSet<>();
|
834
|
Query query = getSession().createQuery(queryStr);
|
835
|
query.setBoolean("publish", publish);
|
836
|
if (relTypeUuids != null && !relTypeUuids.isEmpty()){
|
837
|
query.setParameterList("relTypeUuid", relTypeUuids);
|
838
|
}
|
839
|
@SuppressWarnings("unchecked")
|
840
|
List<List<Integer>> partitionList = splitIdList(query.list(), DEFAULT_PARTITION_SIZE);
|
841
|
for (List<Integer> taxonIdList : partitionList){
|
842
|
List<TaxonBase> taxonList = taxonDao.loadList(taxonIdList, null, null);
|
843
|
for (TaxonBase<?> taxonBase : taxonList){
|
844
|
if (taxonBase != null){
|
845
|
taxonBase.setPublish(publish);
|
846
|
result.add((T)CdmBase.deproxy(taxonBase));
|
847
|
monitor.worked(1);
|
848
|
if (monitor.isCanceled()){
|
849
|
return result;
|
850
|
}
|
851
|
}
|
852
|
}
|
853
|
}
|
854
|
return result;
|
855
|
}
|
856
|
|
857
|
private String forSubtreeSynonymQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex, boolean excludeHybrids, SelectMode mode) {
|
858
|
String queryStr = "SELECT " + mode.hql("syn")
|
859
|
+ " FROM TaxonNode tn "
|
860
|
+ " JOIN tn.taxon t "
|
861
|
+ " JOIN t.synonyms syn LEFT JOIN syn.name n ";
|
862
|
String whereStr = " tn.treeIndex LIKE '%1$s%%' ";
|
863
|
if (!includeSharedTaxa){
|
864
|
whereStr += " AND NOT EXISTS ("
|
865
|
+ "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";
|
866
|
}
|
867
|
whereStr = handleExcludeHybrids(whereStr, excludeHybrids, "syn");
|
868
|
queryStr += " WHERE " + String.format(whereStr, subTreeIndex.toString());
|
869
|
|
870
|
return queryStr;
|
871
|
}
|
872
|
|
873
|
private String handleExcludeHybrids(String whereStr, boolean excludeHybrids, String t) {
|
874
|
if(excludeHybrids){
|
875
|
|
876
|
String hybridWhere = " AND (n is NULL OR "
|
877
|
+ " (n.monomHybrid=0 AND n.binomHybrid=0 "
|
878
|
+ " AND n.trinomHybrid=0 AND n.hybridFormula=0 )) ";
|
879
|
|
880
|
whereStr += hybridWhere; //String.format(hybridWhere, t);
|
881
|
}
|
882
|
return whereStr;
|
883
|
}
|
884
|
|
885
|
private String forSubtreeRelatedTaxaQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex,
|
886
|
boolean excludeHybrids, SelectMode mode) {
|
887
|
String queryStr = "SELECT " + mode.hql("relTax")
|
888
|
+ " FROM TaxonNode tn "
|
889
|
+ " JOIN tn.taxon t "
|
890
|
+ " JOIN t.relationsToThisTaxon rel"
|
891
|
+ " JOIN rel.relatedFrom relTax LEFT JOIN relTax.name n ";
|
892
|
String whereStr =" tn.treeIndex LIKE '%1$s%%' ";
|
893
|
if (!includeSharedTaxa){
|
894
|
//toTaxon should only be used in the given subtree
|
895
|
whereStr += " AND NOT EXISTS ("
|
896
|
+ "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";
|
897
|
//from taxon should not be used in another classification
|
898
|
whereStr += " AND NOT EXISTS ("
|
899
|
+ "FROM TaxonNode tn3 WHERE tn3.taxon = relTax AND tn3.treeIndex not like '%1$s%%') ";
|
900
|
//fromTaxon should not be related as e.g. pro parte synonym or misapplication to
|
901
|
//another taxon which is not part of the subtree
|
902
|
//TODO and has not the publish state
|
903
|
whereStr += " AND NOT EXISTS ("
|
904
|
+ "FROM TaxonNode tn4 JOIN tn4.taxon t2 JOIN t2.relationsToThisTaxon rel2 "
|
905
|
+ " WHERE rel2.relatedFrom = relTax AND tn4.treeIndex not like '%1$s%%' "
|
906
|
+ " AND tn4.taxon.publish != :publish ) ";
|
907
|
}
|
908
|
whereStr = handleExcludeHybrids(whereStr, excludeHybrids, "relTax");
|
909
|
queryStr += " WHERE " + String.format(whereStr, subTreeIndex.toString());
|
910
|
|
911
|
return queryStr;
|
912
|
}
|
913
|
|
914
|
private enum SelectMode{
|
915
|
COUNT(" count(*) "),
|
916
|
ID ("id "),
|
917
|
UUID("uuid "),
|
918
|
FULL("");
|
919
|
private String hql;
|
920
|
SelectMode(String hql){
|
921
|
this.hql = hql;
|
922
|
}
|
923
|
public String hql(String prefix){
|
924
|
switch (this){
|
925
|
case ID:
|
926
|
case UUID:
|
927
|
return CdmUtils.Nz(prefix)+"." + hql;
|
928
|
case FULL:
|
929
|
return CdmUtils.Nz(prefix) + hql;
|
930
|
case COUNT:
|
931
|
default: return hql;
|
932
|
}
|
933
|
|
934
|
}
|
935
|
}
|
936
|
|
937
|
private String forSubtreeAcceptedQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex, boolean excludeHybrids, SelectMode mode) {
|
938
|
String queryStr = "SELECT " + mode.hql("t")
|
939
|
+ " FROM TaxonNode tn JOIN tn.taxon t LEFT JOIN t.name n ";
|
940
|
String whereStr = " tn.treeIndex like '%1$s%%' ";
|
941
|
if (!includeSharedTaxa){
|
942
|
whereStr += " AND NOT EXISTS ("
|
943
|
+ "FROM TaxonNode tn2 WHERE tn2.taxon = t AND tn2.treeIndex not like '%1$s%%') ";
|
944
|
}
|
945
|
whereStr = handleExcludeHybrids(whereStr, excludeHybrids, "t");
|
946
|
queryStr += " WHERE " + String.format(whereStr, subTreeIndex.toString());
|
947
|
|
948
|
return queryStr;
|
949
|
}
|
950
|
|
951
|
@Override
|
952
|
public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, Integer limit, String pattern, boolean searchForClassifications, boolean includeDoubtful) {
|
953
|
|
954
|
Query query = createQueryForUuidAndTitleCache(limit, classification.getUuid(), pattern, includeDoubtful);
|
955
|
@SuppressWarnings("unchecked")
|
956
|
List<SortableTaxonNodeQueryResult> result = query.list();
|
957
|
|
958
|
|
959
|
if (searchForClassifications){
|
960
|
String queryString = "SELECT new " + SortableTaxonNodeQueryResult.class.getName() + "("
|
961
|
+ " node.uuid, node.id, node.classification.titleCache"
|
962
|
+ ") "
|
963
|
+ " FROM TaxonNode AS node "
|
964
|
+ " WHERE node.classification.id = " + classification.getId() +
|
965
|
" AND node.taxon IS NULL";
|
966
|
if (pattern != null){
|
967
|
if (pattern.equals("?")){
|
968
|
limit = null;
|
969
|
} else{
|
970
|
if (!pattern.endsWith("*")){
|
971
|
pattern += "%";
|
972
|
}
|
973
|
pattern = pattern.replace("*", "%");
|
974
|
pattern = pattern.replace("?", "%");
|
975
|
queryString = queryString + " AND node.classification.titleCache LIKE (:pattern) " ;
|
976
|
}
|
977
|
}
|
978
|
query = getSession().createQuery(queryString);
|
979
|
|
980
|
if (limit != null){
|
981
|
query.setMaxResults(limit);
|
982
|
}
|
983
|
|
984
|
if (pattern != null && !pattern.equals("?")){
|
985
|
query.setParameter("pattern", pattern);
|
986
|
}
|
987
|
@SuppressWarnings("unchecked")
|
988
|
List<SortableTaxonNodeQueryResult> resultClassifications = query.list();
|
989
|
|
990
|
result.addAll(resultClassifications);
|
991
|
}
|
992
|
|
993
|
if(result.size() == 0){
|
994
|
return null;
|
995
|
}else{
|
996
|
List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>(result.size());
|
997
|
Collections.sort(result, new SortableTaxonNodeQueryResultComparator());
|
998
|
for (SortableTaxonNodeQueryResult resultDTO : result){
|
999
|
list.add(new UuidAndTitleCache<>(TaxonNode.class, resultDTO.getTaxonNodeUuid(), resultDTO.getTaxonNodeId(), resultDTO.getTaxonTitleCache()));
|
1000
|
}
|
1001
|
|
1002
|
return list;
|
1003
|
}
|
1004
|
}
|
1005
|
|
1006
|
@Override
|
1007
|
public List<TaxonNodeDto> getTaxonNodeDto(Integer limit, String pattern, UUID classificationUuid) {
|
1008
|
String queryString = "SELECT new " + SortableTaxonNodeQueryResult.class.getName() + "("
|
1009
|
+ "tn.uuid, tn.id, t.titleCache, rank "
|
1010
|
+ ") "
|
1011
|
+ " FROM TaxonNode tn "
|
1012
|
+ " INNER JOIN tn.taxon AS t "
|
1013
|
+ " INNER JOIN tn.classification AS cls "
|
1014
|
+ " INNER JOIN t.name AS name "
|
1015
|
+ " LEFT OUTER JOIN name.rank AS rank "
|
1016
|
+ " WHERE t.titleCache LIKE :pattern ";
|
1017
|
if(classificationUuid != null){
|
1018
|
queryString += "AND cls.uuid = :classificationUuid";
|
1019
|
}
|
1020
|
|
1021
|
Query query = getSession().createQuery(queryString);
|
1022
|
|
1023
|
query.setParameter("pattern", pattern.toLowerCase()+"%");
|
1024
|
if(classificationUuid != null){
|
1025
|
query.setParameter("classificationUuid", classificationUuid);
|
1026
|
}
|
1027
|
|
1028
|
@SuppressWarnings("unchecked")
|
1029
|
List<SortableTaxonNodeQueryResult> result = query.list();
|
1030
|
Collections.sort(result, new SortableTaxonNodeQueryResultComparator());
|
1031
|
|
1032
|
List<TaxonNodeDto> list = new ArrayList<>();
|
1033
|
for(SortableTaxonNodeQueryResult queryDTO : result){
|
1034
|
list.add(new TaxonNodeDto(queryDTO.getTaxonNodeUuid(), queryDTO.getTaxonNodeId(), queryDTO.getTaxonTitleCache()));
|
1035
|
}
|
1036
|
return list;
|
1037
|
}
|
1038
|
|
1039
|
@Override
|
1040
|
public List<TaxonNodeDto> getUuidAndTitleCache(Integer limit, String pattern, UUID classificationUuid) {
|
1041
|
return getUuidAndTitleCache(limit, pattern, classificationUuid, false);
|
1042
|
}
|
1043
|
|
1044
|
@Override
|
1045
|
public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
|
1046
|
Classification classification, Integer limit, String pattern, boolean searchForClassifications) {
|
1047
|
return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, limit, pattern, searchForClassifications, false);
|
1048
|
}
|
1049
|
|
1050
|
}
|