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.
9 package eu
.etaxonomy
.cdm
.persistence
.dao
.hibernate
.taxon
;
11 import java
.util
.ArrayList
;
12 import java
.util
.List
;
14 import java
.util
.UUID
;
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
.Transaction
;
28 import org
.hibernate
.criterion
.Criterion
;
29 import org
.hibernate
.criterion
.Projections
;
30 import org
.hibernate
.criterion
.Restrictions
;
31 import org
.hibernate
.search
.FullTextQuery
;
32 import org
.hibernate
.search
.FullTextSession
;
33 import org
.hibernate
.search
.Search
;
34 import org
.hibernate
.search
.SearchFactory
;
35 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
36 import org
.springframework
.beans
.factory
.annotation
.Qualifier
;
37 import org
.springframework
.dao
.DataAccessException
;
38 import org
.springframework
.stereotype
.Repository
;
40 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
41 import eu
.etaxonomy
.cdm
.model
.common
.Marker
;
42 import eu
.etaxonomy
.cdm
.model
.common
.OriginalSource
;
43 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
44 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
45 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
46 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
47 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
48 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
49 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
50 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
51 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
52 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
53 import eu
.etaxonomy
.cdm
.persistence
.dao
.QueryParseException
;
54 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ITitledDao
;
55 import eu
.etaxonomy
.cdm
.persistence
.dao
.hibernate
.AlternativeSpellingSuggestionParser
;
56 import eu
.etaxonomy
.cdm
.persistence
.dao
.hibernate
.common
.IdentifiableDaoBase
;
57 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
58 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
66 @Qualifier("taxonDaoHibernateImpl")
67 public class TaxonDaoHibernateImpl
extends IdentifiableDaoBase
<TaxonBase
> implements ITaxonDao
{
68 private AlternativeSpellingSuggestionParser
<TaxonBase
> alternativeSpellingSuggestionParser
;
71 @SuppressWarnings("unused")
72 private static final Logger logger
= Logger
.getLogger(TaxonDaoHibernateImpl
.class);
74 public TaxonDaoHibernateImpl() {
75 super(TaxonBase
.class);
79 public void setAlternativeSpellingSuggestionParser(AlternativeSpellingSuggestionParser
<TaxonBase
> alternativeSpellingSuggestionParser
) {
80 this.alternativeSpellingSuggestionParser
= alternativeSpellingSuggestionParser
;
84 * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.reference.ReferenceBase)
86 public List
<Taxon
> getRootTaxa(ReferenceBase sec
) {
87 return getRootTaxa(sec
, CdmFetch
.FETCH_CHILDTAXA(), true, false);
93 * @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)
95 public List
<Taxon
> getRootTaxa(ReferenceBase sec
, CdmFetch cdmFetch
, Boolean onlyWithChildren
, Boolean withMisapplications
) {
96 if (onlyWithChildren
== null){
97 onlyWithChildren
= true;
99 if (withMisapplications
== null){
100 withMisapplications
= true;
102 if (cdmFetch
== null){
103 cdmFetch
= CdmFetch
.NO_FETCH();
107 // String query = "from Taxon root ";
108 // query += " where root.taxonomicParentCache is NULL ";
110 // query += " AND root.sec.id = :sec ";
112 // Query q = getSession().createQuery(query);
114 // q.setInteger("sec", sec.getId());
118 Criteria crit
= getSession().createCriteria(Taxon
.class);
119 crit
.add(Restrictions
.isNull("taxonomicParentCache"));
121 crit
.add(Restrictions
.eq("sec", sec
) );
125 if (! cdmFetch
.includes(CdmFetch
.FETCH_CHILDTAXA())){
126 logger
.warn("no child taxa fetch");
127 //TODO overwrite LAZY (SELECT) does not work (bug in hibernate?)
128 crit
.setFetchMode("relationsToThisTaxon.fromTaxon", FetchMode
.LAZY
);
131 List
<Taxon
> results
= new ArrayList
<Taxon
>();
132 for(Taxon taxon
: (List
<Taxon
>) crit
.list()){
134 //TODO create restriction instead
135 if (onlyWithChildren
== false || taxon
.hasTaxonomicChildren()){
136 if (withMisapplications
== true || ! taxon
.isMisappliedName()){
144 public List
<TaxonBase
> getTaxaByName(String queryString
, ReferenceBase sec
) {
146 return getTaxaByName(queryString
, true, sec
);
149 public List
<TaxonBase
> getTaxaByName(String queryString
, Boolean accepted
, ReferenceBase sec
) {
151 Criteria criteria
= null;
152 if (accepted
== true) {
153 criteria
= getSession().createCriteria(Taxon
.class);
155 criteria
= getSession().createCriteria(Synonym
.class);
158 criteria
.setFetchMode( "name", FetchMode
.JOIN
);
159 criteria
.createAlias("name", "name");
162 if(sec
.getId() == 0){
163 getSession().save(sec
);
165 criteria
.add(Restrictions
.eq("sec", sec
) );
167 if (queryString
!= null) {
168 criteria
.add(Restrictions
.ilike("name.nameCache", queryString
));
170 List
<TaxonBase
> results
= criteria
.list();
174 public List
<TaxonBase
> getAllTaxonBases(Integer pagesize
, Integer page
) {
175 Criteria crit
= getSession().createCriteria(TaxonBase
.class);
176 List
<TaxonBase
> results
= crit
.list();
177 // TODO add page & pagesize criteria
181 public List
<Synonym
> getAllSynonyms(Integer limit
, Integer start
) {
182 Criteria crit
= getSession().createCriteria(Synonym
.class);
183 List
<Synonym
> results
= crit
.list();
187 public List
<Taxon
> getAllTaxa(Integer limit
, Integer start
) {
188 Criteria crit
= getSession().createCriteria(Taxon
.class);
189 List
<Taxon
> results
= crit
.list();
193 public List
<RelationshipBase
> getAllRelationships(Integer limit
, Integer start
) {
194 Criteria crit
= getSession().createCriteria(RelationshipBase
.class);
195 List
<RelationshipBase
> results
= crit
.list();
200 public UUID
delete(TaxonBase taxonBase
) throws DataAccessException
{
201 //getSession().update(taxonBase); doesn't work with lazy collections
204 Set
<Annotation
> annotations
= taxonBase
.getAnnotations();
205 for (Annotation annotation
: annotations
){
206 taxonBase
.removeAnnotation(annotation
);
208 } catch (LazyInitializationException e
) {
209 logger
.warn("LazyInitializationException: " + e
);
213 Set
<Marker
> markers
= taxonBase
.getMarkers();
214 for (Marker marker
: markers
){
215 taxonBase
.removeMarker(marker
);
217 } catch (LazyInitializationException e
) {
218 logger
.warn("LazyInitializationException: " + e
);
222 Set
<OriginalSource
> origSources
= taxonBase
.getSources();
223 for (OriginalSource source
: origSources
){
224 taxonBase
.removeSource(source
);
226 } catch (LazyInitializationException e
) {
227 logger
.warn("LazyInitializationException: " + e
);
230 taxonBase
.getName().removeTaxonBase(taxonBase
);
231 if (taxonBase
instanceof Taxon
){
233 Taxon taxon
= (Taxon
)taxonBase
;
234 Set
<TaxonRelationship
> taxRels
= taxon
.getTaxonRelations();
235 for (TaxonRelationship taxRel
: taxRels
){
236 taxon
.removeTaxonRelation(taxRel
);
238 //SynonymRelationships
239 Set
<SynonymRelationship
> synRels
= taxon
.getSynonymRelations();
240 for (SynonymRelationship synRel
: synRels
){
241 taxon
.removeSynonymRelation(synRel
);
244 else if (taxonBase
instanceof Synonym
){
245 Synonym synonym
= (Synonym
)taxonBase
;
246 Set
<SynonymRelationship
> synRels
= synonym
.getSynonymRelations();
247 for (SynonymRelationship synRel
: synRels
){
248 synonym
.removeSynonymRelation(synRel
);
251 return super.delete(taxonBase
);
255 // TODO add generic return type !!
256 public List
findByName(String queryString
, ITitledDao
.MATCH_MODE matchMode
, int page
, int pagesize
, boolean onlyAcccepted
) {
257 ArrayList
<Criterion
> criteria
= new ArrayList
<Criterion
>();
258 //TODO ... Restrictions.eq(propertyName, value)
259 return super.findByTitle(queryString
, matchMode
, page
, pagesize
, criteria
);
263 public int countMatchesByName(String queryString
, ITitledDao
.MATCH_MODE matchMode
, boolean onlyAcccepted
) {
265 Criteria crit
= getSession().createCriteria(type
);
266 crit
.add(Restrictions
.ilike("persistentTitleCache", matchMode
.queryStringFrom(queryString
)));
267 crit
.setProjection(Projections
.rowCount());
268 int result
= ((Integer
)crit
.list().get(0)).intValue();
273 public int countMatchesByName(String queryString
, ITitledDao
.MATCH_MODE matchMode
, boolean onlyAcccepted
, List
<Criterion
> criteria
) {
275 Criteria crit
= getSession().createCriteria(type
);
276 crit
.add(Restrictions
.ilike("persistentTitleCache", matchMode
.queryStringFrom(queryString
)));
277 if(criteria
!= null){
278 for (Criterion criterion
: criteria
) {
282 crit
.setProjection(Projections
.rowCount());
283 int result
= ((Integer
)crit
.list().get(0)).intValue();
287 public int countRelatedTaxa(Taxon taxon
, TaxonRelationshipType type
) {
291 query
= getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship.relatedTo = :relatedTo");
293 query
= getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship.relatedTo = :relatedTo and taxonRelationship.type = :type");
294 query
.setParameter("type",type
);
297 query
.setParameter("relatedTo", taxon
);
299 return ((Long
)query
.uniqueResult()).intValue();
302 public int countSynonyms(Taxon taxon
, SynonymRelationshipType type
) {
306 query
= getSession().createQuery("select count(synonymRelationship) from SynonymRelationship synonymRelationship where synonymRelationship.relatedTo = :relatedTo");
308 query
= getSession().createQuery("select count(synonymRelationship) from SynonymRelationship synonymRelationship where synonymRelationship.relatedTo = :relatedTo and synonymRelationship.type = :type");
309 query
.setParameter("type",type
);
312 query
.setParameter("relatedTo", taxon
);
314 return ((Long
)query
.uniqueResult()).intValue();
317 public int countTaxa(String queryString
, Boolean accepted
) {
318 QueryParser queryParser
= new QueryParser("name.persistentTitleCache", new SimpleAnalyzer());
321 org
.apache
.lucene
.search
.Query query
= queryParser
.parse(queryString
);
323 FullTextSession fullTextSession
= Search
.createFullTextSession(this.getSession());
324 org
.hibernate
.search
.FullTextQuery fullTextQuery
= null;
326 if(accepted
== null) {
327 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, TaxonBase
.class);
330 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, Taxon
.class);
332 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, Synonym
.class);
336 Integer result
= fullTextQuery
.getResultSize();
339 } catch (ParseException e
) {
340 throw new QueryParseException(e
, queryString
);
344 public int countTaxaByName(String queryString
, Boolean accepted
, ReferenceBase sec
) {
346 Criteria criteria
= null;
348 if (accepted
== true) {
349 criteria
= getSession().createCriteria(Taxon
.class);
351 criteria
= getSession().createCriteria(Synonym
.class);
354 criteria
.setFetchMode( "name", FetchMode
.JOIN
);
355 criteria
.createAlias("name", "name");
358 if(sec
.getId() == 0){
359 getSession().save(sec
);
361 criteria
.add(Restrictions
.eq("sec", sec
) );
363 if (queryString
!= null) {
364 criteria
.add(Restrictions
.ilike("name.nameCache", queryString
));
366 criteria
.setProjection(Projections
.projectionList().add(Projections
.rowCount()));
368 return (Integer
)criteria
.uniqueResult();
371 public int countTaxaByName(Boolean accepted
, String genusOrUninomial
, String infraGenericEpithet
, String specificEpithet
, String infraSpecificEpithet
, Rank rank
) {
372 Criteria criteria
= null;
374 if(accepted
== null) {
375 criteria
= getSession().createCriteria(TaxonBase
.class);
378 criteria
= getSession().createCriteria(Taxon
.class);
380 criteria
= getSession().createCriteria(Synonym
.class);
384 criteria
.setFetchMode( "name", FetchMode
.JOIN
);
385 criteria
.createAlias("name", "name");
387 if(genusOrUninomial
!= null) {
388 criteria
.add(Restrictions
.eq("name.genusOrUninomial", genusOrUninomial
));
391 if(infraGenericEpithet
!= null) {
392 criteria
.add(Restrictions
.eq("name.infraGenericEpithet", infraGenericEpithet
));
395 if(specificEpithet
!= null) {
396 criteria
.add(Restrictions
.eq("name.specificEpithet", specificEpithet
));
399 if(infraSpecificEpithet
!= null) {
400 criteria
.add(Restrictions
.eq("name.infraSpecificEpithet", infraSpecificEpithet
));
404 criteria
.add(Restrictions
.eq("name.rank", rank
));
407 criteria
.setProjection(Projections
.projectionList().add(Projections
.rowCount()));
409 return (Integer
)criteria
.uniqueResult();
412 public List
<TaxonBase
> findTaxaByName(Boolean accepted
, String genusOrUninomial
, String infraGenericEpithet
, String specificEpithet
, String infraSpecificEpithet
, Rank rank
, Integer pageSize
, Integer pageNumber
) {
413 Criteria criteria
= null;
415 if(accepted
== null) {
416 criteria
= getSession().createCriteria(TaxonBase
.class);
419 criteria
= getSession().createCriteria(Taxon
.class);
421 criteria
= getSession().createCriteria(Synonym
.class);
425 criteria
.setFetchMode( "name", FetchMode
.JOIN
);
426 criteria
.createAlias("name", "name");
428 if(genusOrUninomial
!= null) {
429 criteria
.add(Restrictions
.eq("name.genusOrUninomial", genusOrUninomial
));
432 if(infraGenericEpithet
!= null) {
433 criteria
.add(Restrictions
.eq("name.infraGenericEpithet", infraGenericEpithet
));
435 criteria
.add(Restrictions
.isNull("name.infraGenericEpithet"));
438 if(specificEpithet
!= null) {
439 criteria
.add(Restrictions
.eq("name.specificEpithet", specificEpithet
));
442 if(infraSpecificEpithet
!= null) {
443 criteria
.add(Restrictions
.eq("name.infraSpecificEpithet", infraSpecificEpithet
));
447 criteria
.add(Restrictions
.eq("name.rank", rank
));
450 if(pageSize
!= null) {
451 criteria
.setMaxResults(pageSize
);
452 if(pageNumber
!= null) {
453 criteria
.setFirstResult(pageNumber
* pageSize
);
455 criteria
.setFirstResult(0);
459 return (List
<TaxonBase
>)criteria
.list();
462 public List
<TaxonRelationship
> getRelatedTaxa(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
) {
466 query
= getSession().createQuery("select taxonRelationship from TaxonRelationship taxonRelationship join fetch taxonRelationship.relatedFrom where taxonRelationship.relatedTo = :relatedTo");
468 query
= getSession().createQuery("select taxonRelationship from TaxonRelationship taxonRelationship join fetch taxonRelationship.relatedFrom where taxonRelationship.relatedTo = :relatedTo and taxonRelationship.type = :type");
469 query
.setParameter("type",type
);
472 query
.setParameter("relatedTo", taxon
);
474 if(pageSize
!= null) {
475 query
.setMaxResults(pageSize
);
476 if(pageNumber
!= null) {
477 query
.setFirstResult(pageNumber
* pageSize
);
479 query
.setFirstResult(0);
483 return (List
<TaxonRelationship
>)query
.list();
486 public List
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
) {
490 query
= getSession().createQuery("select synonymRelationship from SynonymRelationship synonymRelationship join fetch synonymRelationship.relatedFrom where synonymRelationship.relatedTo = :relatedTo");
492 query
= getSession().createQuery("select synonymRelationship from SynonymRelationship synonymRelationship join fetch synonymRelationship.relatedFrom where synonymRelationship.relatedTo = :relatedTo and synonymRelationship.type = :type");
493 query
.setParameter("type",type
);
496 query
.setParameter("relatedTo", taxon
);
498 if(pageSize
!= null) {
499 query
.setMaxResults(pageSize
);
500 if(pageNumber
!= null) {
501 query
.setFirstResult(pageNumber
* pageSize
);
503 query
.setFirstResult(0);
507 return (List
<SynonymRelationship
>)query
.list();
510 public List
<TaxonBase
> searchTaxa(String queryString
, Boolean accepted
, Integer pageSize
, Integer pageNumber
) {
511 QueryParser queryParser
= new QueryParser("name.persistentTitleCache", new SimpleAnalyzer());
512 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
515 org
.apache
.lucene
.search
.Query query
= queryParser
.parse(queryString
);
517 FullTextSession fullTextSession
= Search
.createFullTextSession(getSession());
518 org
.hibernate
.search
.FullTextQuery fullTextQuery
= null;
519 Criteria criteria
= null;
521 if(accepted
== null) {
522 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, TaxonBase
.class);
523 criteria
= getSession().createCriteria( TaxonBase
.class );
526 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, Taxon
.class);
527 criteria
= getSession().createCriteria( Taxon
.class );
529 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, Synonym
.class);
530 criteria
= getSession().createCriteria( Synonym
.class );
534 org
.apache
.lucene
.search
.Sort sort
= new Sort(new SortField("name.titleCache_forSort"));
535 fullTextQuery
.setSort(sort
);
537 criteria
.setFetchMode( "name", FetchMode
.JOIN
);
538 fullTextQuery
.setCriteriaQuery(criteria
);
540 if(pageSize
!= null) {
541 fullTextQuery
.setMaxResults(pageSize
);
542 if(pageNumber
!= null) {
543 fullTextQuery
.setFirstResult(pageNumber
* pageSize
);
545 fullTextQuery
.setFirstResult(0);
549 return (List
<TaxonBase
>)fullTextQuery
.list();
551 } catch (ParseException e
) {
552 throw new QueryParseException(e
, queryString
);
556 public void purgeIndex() {
557 FullTextSession fullTextSession
= Search
.createFullTextSession(getSession());
559 fullTextSession
.purgeAll(type
); // remove all taxon base from indexes
560 // fullTextSession.flushToIndexes() not implemented in 3.0.0.GA
563 public void rebuildIndex() {
564 FullTextSession fullTextSession
= Search
.createFullTextSession(getSession());
566 for(TaxonBase taxonBase
: list(null,null)) { // re-index all taxon base
567 Hibernate
.initialize(taxonBase
.getName());
568 fullTextSession
.index(taxonBase
);
570 // fullTextSession.flushToIndexes() not implemented in 3.0.0.GA
573 public void optimizeIndex() {
574 FullTextSession fullTextSession
= Search
.createFullTextSession(getSession());
575 SearchFactory searchFactory
= fullTextSession
.getSearchFactory();
576 searchFactory
.optimize(type
); // optimize the indices ()
577 // fullTextSession.flushToIndexes() not implemented in 3.0.0.GA
580 public String
suggestQuery(String queryString
) {
582 String alternativeQueryString
= null;
583 alternativeSpellingSuggestionParser
.parse(queryString
);
584 org
.apache
.lucene
.search
.Query alternativeQuery
= alternativeSpellingSuggestionParser
.suggest(queryString
);
585 if(alternativeQuery
!= null) {
586 alternativeQueryString
= alternativeQuery
.toString("name.persistentTitleCache");
588 return alternativeQueryString
;
589 } catch (ParseException e
) {
590 throw new QueryParseException(e
, queryString
);