1a02c3dfc4e2fc984981c8950db8387715e383aa
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / taxon / TaxonDaoHibernateImpl.java
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 package eu.etaxonomy.cdm.persistence.dao.hibernate.taxon;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Set;
14 import java.util.UUID;
15
16 import org.apache.log4j.Logger;
17 import org.apache.lucene.analysis.SimpleAnalyzer;
18 import org.apache.lucene.queryParser.ParseException;
19 import org.apache.lucene.queryParser.QueryParser;
20 import org.apache.lucene.search.Sort;
21 import org.apache.lucene.search.SortField;
22 import org.hibernate.Criteria;
23 import org.hibernate.FetchMode;
24 import org.hibernate.Hibernate;
25 import org.hibernate.LazyInitializationException;
26 import org.hibernate.Query;
27 import org.hibernate.criterion.Criterion;
28 import org.hibernate.criterion.Projections;
29 import org.hibernate.criterion.Restrictions;
30 import org.hibernate.search.FullTextSession;
31 import org.hibernate.search.Search;
32 import org.hibernate.search.SearchFactory;
33 import org.springframework.beans.factory.annotation.Autowired;
34 import org.springframework.beans.factory.annotation.Qualifier;
35 import org.springframework.dao.DataAccessException;
36 import org.springframework.stereotype.Repository;
37
38 import eu.etaxonomy.cdm.model.common.Annotation;
39 import eu.etaxonomy.cdm.model.common.Marker;
40 import eu.etaxonomy.cdm.model.common.OriginalSource;
41 import eu.etaxonomy.cdm.model.common.RelationshipBase;
42 import eu.etaxonomy.cdm.model.name.Rank;
43 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
44 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
45 import eu.etaxonomy.cdm.model.taxon.Synonym;
46 import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
47 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
48 import eu.etaxonomy.cdm.model.taxon.Taxon;
49 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
50 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
51 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
52 import eu.etaxonomy.cdm.persistence.dao.QueryParseException;
53 import eu.etaxonomy.cdm.persistence.dao.common.ITitledDao;
54 import eu.etaxonomy.cdm.persistence.dao.hibernate.AlternativeSpellingSuggestionParser;
55 import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;
56 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
57 import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;
58
59 /**
60 * @author a.mueller
61 * @created 24.11.2008
62 * @version 1.0
63 */
64 @Repository
65 @Qualifier("taxonDaoHibernateImpl")
66 public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implements ITaxonDao {
67 private AlternativeSpellingSuggestionParser<TaxonBase> alternativeSpellingSuggestionParser;
68
69 private static final Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);
70
71 public TaxonDaoHibernateImpl() {
72 super(TaxonBase.class);
73 }
74
75 @Autowired(required = false) //TODO switched of because it caused problems when starting CdmApplicationController
76 public void setAlternativeSpellingSuggestionParser(AlternativeSpellingSuggestionParser<TaxonBase> alternativeSpellingSuggestionParser) {
77 this.alternativeSpellingSuggestionParser = alternativeSpellingSuggestionParser;
78 }
79
80 /* (non-Javadoc)
81 * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.reference.ReferenceBase)
82 */
83 public List<Taxon> getRootTaxa(ReferenceBase sec) {
84 return getRootTaxa(sec, CdmFetch.FETCH_CHILDTAXA(), true, false);
85 }
86
87
88
89 /* (non-Javadoc)
90 * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.reference.ReferenceBase, eu.etaxonomy.cdm.persistence.fetch.CdmFetch, java.lang.Boolean, java.lang.Boolean)
91 */
92 public List<Taxon> getRootTaxa(ReferenceBase sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications) {
93 if (onlyWithChildren == null){
94 onlyWithChildren = true;
95 }
96 if (withMisapplications == null){
97 withMisapplications = true;
98 }
99 if (cdmFetch == null){
100 cdmFetch = CdmFetch.NO_FETCH();
101 }
102
103
104 // String query = "from Taxon root ";
105 // query += " where root.taxonomicParentCache is NULL ";
106 // if (sec != null){
107 // query += " AND root.sec.id = :sec ";
108 // }
109 // Query q = getSession().createQuery(query);
110 // if (sec != null){
111 // q.setInteger("sec", sec.getId());
112 // }
113
114
115 Criteria crit = getSession().createCriteria(Taxon.class);
116 crit.add(Restrictions.isNull("taxonomicParentCache"));
117 if (sec != null){
118 crit.add(Restrictions.eq("sec", sec) );
119 }
120
121
122 if (! cdmFetch.includes(CdmFetch.FETCH_CHILDTAXA())){
123 logger.warn("no child taxa fetch");
124 //TODO overwrite LAZY (SELECT) does not work (bug in hibernate?)
125 crit.setFetchMode("relationsToThisTaxon.fromTaxon", FetchMode.LAZY);
126 }
127
128 List<Taxon> results = new ArrayList<Taxon>();
129 for(Taxon taxon : (List<Taxon>) crit.list()){
130 //childTaxa
131 //TODO create restriction instead
132 if (onlyWithChildren == false || taxon.hasTaxonomicChildren()){
133 if (withMisapplications == true || ! taxon.isMisappliedName()){
134 results.add(taxon);
135 }
136 }
137 }
138 return results;
139 }
140
141 public List<TaxonBase> getTaxaByName(String queryString, ReferenceBase sec) {
142
143 return getTaxaByName(queryString, true, sec);
144 }
145
146 public List<TaxonBase> getTaxaByName(String queryString, Boolean accepted, ReferenceBase sec) {
147
148 Criteria criteria = null;
149 if (accepted == true) {
150 criteria = getSession().createCriteria(Taxon.class);
151 } else {
152 criteria = getSession().createCriteria(Synonym.class);
153 }
154
155 criteria.setFetchMode( "name", FetchMode.JOIN );
156 criteria.createAlias("name", "name");
157
158 if (sec != null){
159 if(sec.getId() == 0){
160 getSession().save(sec);
161 }
162 criteria.add(Restrictions.eq("sec", sec ) );
163 }
164 if (queryString != null) {
165 criteria.add(Restrictions.ilike("name.nameCache", queryString));
166 }
167 List<TaxonBase> results = criteria.list();
168 return results;
169 }
170
171 public List<TaxonBase> getAllTaxonBases(Integer pagesize, Integer page) {
172 Criteria crit = getSession().createCriteria(TaxonBase.class);
173 List<TaxonBase> results = crit.list();
174 // TODO add page & pagesize criteria
175 return results;
176 }
177
178 public List<Synonym> getAllSynonyms(Integer limit, Integer start) {
179 Criteria crit = getSession().createCriteria(Synonym.class);
180 List<Synonym> results = crit.list();
181 return results;
182 }
183
184 public List<Taxon> getAllTaxa(Integer limit, Integer start) {
185 Criteria crit = getSession().createCriteria(Taxon.class);
186 List<Taxon> results = crit.list();
187 return results;
188 }
189
190 public List<RelationshipBase> getAllRelationships(Integer limit, Integer start) {
191 Criteria crit = getSession().createCriteria(RelationshipBase.class);
192 List<RelationshipBase> results = crit.list();
193 return results;
194 }
195
196 @Override
197 public UUID delete(TaxonBase taxonBase) throws DataAccessException{
198 //getSession().update(taxonBase); doesn't work with lazy collections
199 if (taxonBase == null){
200 logger.warn("TaxonBase was 'null'");
201 return null;
202 }
203 //annotations
204 try {
205 Set<Annotation> annotations = taxonBase.getAnnotations();
206 for (Annotation annotation: annotations){
207 taxonBase.removeAnnotation(annotation);
208 }
209 } catch (LazyInitializationException e) {
210 logger.warn("LazyInitializationException: " + e);
211 }
212 //markers
213 try {
214 Set<Marker> markers = taxonBase.getMarkers();
215 for (Marker marker: markers){
216 taxonBase.removeMarker(marker);
217 }
218 } catch (LazyInitializationException e) {
219 logger.warn("LazyInitializationException: " + e);
220 }
221 //originalSource
222 try {
223 Set<OriginalSource> origSources = taxonBase.getSources();
224 for (OriginalSource source: origSources){
225 taxonBase.removeSource(source);
226 }
227 } catch (LazyInitializationException e) {
228 logger.warn("LazyInitializationException: " + e);
229 }
230 //is Taxon
231 TaxonNameBase taxonNameBase =taxonBase.getName();
232 if (taxonNameBase != null){
233 taxonNameBase.removeTaxonBase(taxonBase);
234 }
235 if (taxonBase instanceof Taxon){
236 //taxonRelationships
237 Taxon taxon = (Taxon)taxonBase;
238 Set<TaxonRelationship> taxRels = taxon.getTaxonRelations();
239 for (TaxonRelationship taxRel: taxRels){
240 taxon.removeTaxonRelation(taxRel);
241 } ;
242 //SynonymRelationships
243 Set<SynonymRelationship> synRels = taxon.getSynonymRelations();
244 for (SynonymRelationship synRel: synRels){
245 taxon.removeSynonymRelation(synRel);
246 } ;
247 }//is Synonym
248 else if (taxonBase instanceof Synonym){
249 Synonym synonym = (Synonym)taxonBase;
250 Set<SynonymRelationship> synRels = synonym.getSynonymRelations();
251 for (SynonymRelationship synRel: synRels){
252 synonym.removeSynonymRelation(synRel);
253 } ;
254 }
255 return super.delete(taxonBase);
256 }
257
258
259 // TODO add generic return type !!
260 public List findByName(String queryString, ITitledDao.MATCH_MODE matchMode, int page, int pagesize, boolean onlyAcccepted) {
261 ArrayList<Criterion> criteria = new ArrayList<Criterion>();
262 //TODO ... Restrictions.eq(propertyName, value)
263 return super.findByTitle(queryString, matchMode, page, pagesize, criteria);
264
265 }
266
267 public int countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted) {
268
269 Criteria crit = getSession().createCriteria(type);
270 crit.add(Restrictions.ilike("persistentTitleCache", matchMode.queryStringFrom(queryString)));
271 crit.setProjection(Projections.rowCount());
272 int result = ((Integer)crit.list().get(0)).intValue();
273 return result;
274 }
275
276
277 public int countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted, List<Criterion> criteria) {
278
279 Criteria crit = getSession().createCriteria(type);
280 crit.add(Restrictions.ilike("persistentTitleCache", matchMode.queryStringFrom(queryString)));
281 if(criteria != null){
282 for (Criterion criterion : criteria) {
283 crit.add(criterion);
284 }
285 }
286 crit.setProjection(Projections.rowCount());
287 int result = ((Integer)crit.list().get(0)).intValue();
288 return result;
289 }
290
291 public int countRelatedTaxa(Taxon taxon, TaxonRelationshipType type) {
292 Query query = null;
293
294 if(type == null) {
295 query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship.relatedTo = :relatedTo");
296 } else {
297 query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship.relatedTo = :relatedTo and taxonRelationship.type = :type");
298 query.setParameter("type",type);
299 }
300
301 query.setParameter("relatedTo", taxon);
302
303 return ((Long)query.uniqueResult()).intValue();
304 }
305
306 public int countSynonyms(Taxon taxon, SynonymRelationshipType type) {
307 Query query = null;
308
309 if(type == null) {
310 query = getSession().createQuery("select count(synonymRelationship) from SynonymRelationship synonymRelationship where synonymRelationship.relatedTo = :relatedTo");
311 } else {
312 query = getSession().createQuery("select count(synonymRelationship) from SynonymRelationship synonymRelationship where synonymRelationship.relatedTo = :relatedTo and synonymRelationship.type = :type");
313 query.setParameter("type",type);
314 }
315
316 query.setParameter("relatedTo", taxon);
317
318 return ((Long)query.uniqueResult()).intValue();
319 }
320
321 public int countTaxa(String queryString, Boolean accepted) {
322 QueryParser queryParser = new QueryParser("name.persistentTitleCache", new SimpleAnalyzer());
323
324 try {
325 org.apache.lucene.search.Query query = queryParser.parse(queryString);
326
327 FullTextSession fullTextSession = Search.createFullTextSession(this.getSession());
328 org.hibernate.search.FullTextQuery fullTextQuery = null;
329
330 if(accepted == null) {
331 fullTextQuery = fullTextSession.createFullTextQuery(query, TaxonBase.class);
332 } else {
333 if(accepted) {
334 fullTextQuery = fullTextSession.createFullTextQuery(query, Taxon.class);
335 } else {
336 fullTextQuery = fullTextSession.createFullTextQuery(query, Synonym.class);
337 }
338 }
339
340 Integer result = fullTextQuery.getResultSize();
341 return result;
342
343 } catch (ParseException e) {
344 throw new QueryParseException(e, queryString);
345 }
346 }
347
348 public int countTaxaByName(String queryString, Boolean accepted, ReferenceBase sec) {
349
350 Criteria criteria = null;
351
352 if (accepted == true) {
353 criteria = getSession().createCriteria(Taxon.class);
354 } else {
355 criteria = getSession().createCriteria(Synonym.class);
356 }
357
358 criteria.setFetchMode( "name", FetchMode.JOIN );
359 criteria.createAlias("name", "name");
360
361 if (sec != null){
362 if(sec.getId() == 0){
363 getSession().save(sec);
364 }
365 criteria.add(Restrictions.eq("sec", sec ) );
366 }
367 if (queryString != null) {
368 criteria.add(Restrictions.ilike("name.nameCache", queryString));
369 }
370 criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
371
372 return (Integer)criteria.uniqueResult();
373 }
374
375 public int countTaxaByName(Boolean accepted, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, Rank rank) {
376 Criteria criteria = null;
377
378 if(accepted == null) {
379 criteria = getSession().createCriteria(TaxonBase.class);
380 } else {
381 if(accepted) {
382 criteria = getSession().createCriteria(Taxon.class);
383 } else {
384 criteria = getSession().createCriteria(Synonym.class);
385 }
386 }
387
388 criteria.setFetchMode( "name", FetchMode.JOIN );
389 criteria.createAlias("name", "name");
390
391 if(genusOrUninomial != null) {
392 criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));
393 }
394
395 if(infraGenericEpithet != null) {
396 criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));
397 }
398
399 if(specificEpithet != null) {
400 criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));
401 }
402
403 if(infraSpecificEpithet != null) {
404 criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));
405 }
406
407 if(rank != null) {
408 criteria.add(Restrictions.eq("name.rank", rank));
409 }
410
411 criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
412
413 return (Integer)criteria.uniqueResult();
414 }
415
416 public List<TaxonBase> findTaxaByName(Boolean accepted, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, Rank rank, Integer pageSize, Integer pageNumber) {
417 Criteria criteria = null;
418
419 if(accepted == null) {
420 criteria = getSession().createCriteria(TaxonBase.class);
421 } else {
422 if(accepted) {
423 criteria = getSession().createCriteria(Taxon.class);
424 } else {
425 criteria = getSession().createCriteria(Synonym.class);
426 }
427 }
428
429 criteria.setFetchMode( "name", FetchMode.JOIN );
430 criteria.createAlias("name", "name");
431
432 if(genusOrUninomial != null) {
433 criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));
434 }
435
436 if(infraGenericEpithet != null) {
437 criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));
438 } else {
439 criteria.add(Restrictions.isNull("name.infraGenericEpithet"));
440 }
441
442 if(specificEpithet != null) {
443 criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));
444 }
445
446 if(infraSpecificEpithet != null) {
447 criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));
448 }
449
450 if(rank != null) {
451 criteria.add(Restrictions.eq("name.rank", rank));
452 }
453
454 if(pageSize != null) {
455 criteria.setMaxResults(pageSize);
456 if(pageNumber != null) {
457 criteria.setFirstResult(pageNumber * pageSize);
458 } else {
459 criteria.setFirstResult(0);
460 }
461 }
462
463 return (List<TaxonBase>)criteria.list();
464 }
465
466 public List<TaxonRelationship> getRelatedTaxa(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber) {
467 Query query = null;
468
469 if(type == null) {
470 query = getSession().createQuery("select taxonRelationship from TaxonRelationship taxonRelationship join fetch taxonRelationship.relatedFrom where taxonRelationship.relatedTo = :relatedTo");
471 } else {
472 query = getSession().createQuery("select taxonRelationship from TaxonRelationship taxonRelationship join fetch taxonRelationship.relatedFrom where taxonRelationship.relatedTo = :relatedTo and taxonRelationship.type = :type");
473 query.setParameter("type",type);
474 }
475
476 query.setParameter("relatedTo", taxon);
477
478 if(pageSize != null) {
479 query.setMaxResults(pageSize);
480 if(pageNumber != null) {
481 query.setFirstResult(pageNumber * pageSize);
482 } else {
483 query.setFirstResult(0);
484 }
485 }
486
487 return (List<TaxonRelationship>)query.list();
488 }
489
490 public List<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber) {
491 Query query = null;
492
493 if(type == null) {
494 query = getSession().createQuery("select synonymRelationship from SynonymRelationship synonymRelationship join fetch synonymRelationship.relatedFrom where synonymRelationship.relatedTo = :relatedTo");
495 } else {
496 query = getSession().createQuery("select synonymRelationship from SynonymRelationship synonymRelationship join fetch synonymRelationship.relatedFrom where synonymRelationship.relatedTo = :relatedTo and synonymRelationship.type = :type");
497 query.setParameter("type",type);
498 }
499
500 query.setParameter("relatedTo", taxon);
501
502 if(pageSize != null) {
503 query.setMaxResults(pageSize);
504 if(pageNumber != null) {
505 query.setFirstResult(pageNumber * pageSize);
506 } else {
507 query.setFirstResult(0);
508 }
509 }
510
511 return (List<SynonymRelationship>)query.list();
512 }
513
514 public List<TaxonBase> searchTaxa(String queryString, Boolean accepted, Integer pageSize, Integer pageNumber) {
515 QueryParser queryParser = new QueryParser("name.persistentTitleCache", new SimpleAnalyzer());
516 List<TaxonBase> results = new ArrayList<TaxonBase>();
517
518 try {
519 org.apache.lucene.search.Query query = queryParser.parse(queryString);
520
521 FullTextSession fullTextSession = Search.createFullTextSession(getSession());
522 org.hibernate.search.FullTextQuery fullTextQuery = null;
523 Criteria criteria = null;
524
525 if(accepted == null) {
526 fullTextQuery = fullTextSession.createFullTextQuery(query, TaxonBase.class);
527 criteria = getSession().createCriteria( TaxonBase.class );
528 } else {
529 if(accepted) {
530 fullTextQuery = fullTextSession.createFullTextQuery(query, Taxon.class);
531 criteria = getSession().createCriteria( Taxon.class );
532 } else {
533 fullTextQuery = fullTextSession.createFullTextQuery(query, Synonym.class);
534 criteria = getSession().createCriteria( Synonym.class );
535 }
536 }
537
538 org.apache.lucene.search.Sort sort = new Sort(new SortField("name.titleCache_forSort"));
539 fullTextQuery.setSort(sort);
540
541 criteria.setFetchMode( "name", FetchMode.JOIN );
542 fullTextQuery.setCriteriaQuery(criteria);
543
544 if(pageSize != null) {
545 fullTextQuery.setMaxResults(pageSize);
546 if(pageNumber != null) {
547 fullTextQuery.setFirstResult(pageNumber * pageSize);
548 } else {
549 fullTextQuery.setFirstResult(0);
550 }
551 }
552
553 return (List<TaxonBase>)fullTextQuery.list();
554
555 } catch (ParseException e) {
556 throw new QueryParseException(e, queryString);
557 }
558 }
559
560 public void purgeIndex() {
561 FullTextSession fullTextSession = Search.createFullTextSession(getSession());
562
563 fullTextSession.purgeAll(type); // remove all taxon base from indexes
564 // fullTextSession.flushToIndexes() not implemented in 3.0.0.GA
565 }
566
567 public void rebuildIndex() {
568 FullTextSession fullTextSession = Search.createFullTextSession(getSession());
569
570 for(TaxonBase taxonBase : list(null,null)) { // re-index all taxon base
571 Hibernate.initialize(taxonBase.getName());
572 fullTextSession.index(taxonBase);
573 }
574 // fullTextSession.flushToIndexes() not implemented in 3.0.0.GA
575 }
576
577 public void optimizeIndex() {
578 FullTextSession fullTextSession = Search.createFullTextSession(getSession());
579 SearchFactory searchFactory = fullTextSession.getSearchFactory();
580 searchFactory.optimize(type); // optimize the indices ()
581 // fullTextSession.flushToIndexes() not implemented in 3.0.0.GA
582 }
583
584 public String suggestQuery(String queryString) {
585 try {
586 String alternativeQueryString = null;
587 alternativeSpellingSuggestionParser.parse(queryString);
588 org.apache.lucene.search.Query alternativeQuery = alternativeSpellingSuggestionParser.suggest(queryString);
589 if(alternativeQuery != null) {
590 alternativeQueryString = alternativeQuery.toString("name.persistentTitleCache");
591 }
592 return alternativeQueryString;
593 } catch (ParseException e) {
594 throw new QueryParseException(e, queryString);
595 }
596 }
597 }