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
.common
;
12 import java
.util
.ArrayList
;
13 import java
.util
.List
;
14 import java
.util
.UUID
;
16 import org
.apache
.log4j
.Logger
;
17 import org
.apache
.lucene
.analysis
.standard
.StandardAnalyzer
;
18 import org
.apache
.lucene
.queryParser
.ParseException
;
19 import org
.apache
.lucene
.queryParser
.QueryParser
;
20 import org
.hibernate
.Criteria
;
21 import org
.hibernate
.Query
;
22 import org
.hibernate
.Session
;
23 import org
.hibernate
.criterion
.Criterion
;
24 import org
.hibernate
.criterion
.Order
;
25 import org
.hibernate
.criterion
.Projections
;
26 import org
.hibernate
.criterion
.Restrictions
;
27 import org
.hibernate
.envers
.query
.AuditEntity
;
28 import org
.hibernate
.envers
.query
.AuditQuery
;
29 import org
.hibernate
.search
.FullTextSession
;
30 import org
.hibernate
.search
.Search
;
31 import org
.hibernate
.search
.SearchFactory
;
33 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
34 import eu
.etaxonomy
.cdm
.model
.common
.Credit
;
35 import eu
.etaxonomy
.cdm
.model
.common
.IIdentifiableEntity
;
36 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
37 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
38 import eu
.etaxonomy
.cdm
.model
.common
.LSID
;
39 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
40 import eu
.etaxonomy
.cdm
.model
.media
.Rights
;
41 import eu
.etaxonomy
.cdm
.persistence
.dao
.QueryParseException
;
42 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IIdentifiableDao
;
43 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
44 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
47 public class IdentifiableDaoBase
<T
extends IdentifiableEntity
> extends AnnotatableDaoImpl
<T
> implements IIdentifiableDao
<T
>{
48 @SuppressWarnings("unused")
49 private static final Logger logger
= Logger
.getLogger(IdentifiableDaoBase
.class);
50 protected String defaultField
= "titleCache_tokenized";
51 protected Class
<?
extends T
> indexedClasses
[];
55 public IdentifiableDaoBase(Class
<T
> type
) {
60 * @see eu.etaxonomy.cdm.persistence.dao.common.ITitledDao#findByTitle(java.lang.String)
62 public List
<T
> findByTitle(String queryString
) {
63 return findByTitle(queryString
, null);
67 * @see eu.etaxonomy.cdm.persistence.dao.common.ITitledDao#findByTitle(java.lang.String)
69 public List
<T
> findByTitle(String queryString
, CdmBase sessionObject
) {
71 * FIXME why do we need to call update in a find* method? I don't know for sure
72 * that this is a good idea . . .
74 Session session
= getSession();
75 if ( sessionObject
!= null ) {
76 session
.update(sessionObject
);
78 checkNotInPriorView("IdentifiableDaoBase.findByTitle(String queryString, CdmBase sessionObject)");
79 Criteria crit
= session
.createCriteria(type
);
80 crit
.add(Restrictions
.ilike("titleCache", queryString
));
81 List
<T
> results
= crit
.list();
82 List
<String
> propertyPaths
= null;
83 defaultBeanInitializer
.initializeAll(results
, propertyPaths
);
87 public List
<T
> findByTitleAndClass(String queryString
, Class
<T
> clazz
) {
88 checkNotInPriorView("IdentifiableDaoBase.findByTitleAndClass(String queryString, Class<T> clazz)");
89 Criteria crit
= getSession().createCriteria(clazz
);
90 crit
.add(Restrictions
.ilike("titleCache", queryString
));
91 List
<T
> results
= crit
.list();
95 public List
<T
> findTitleCache(Class
<?
extends T
> clazz
, String queryString
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, MatchMode matchMode
){
97 Query query
= prepareFindTitleCache(clazz
, queryString
, pageSize
,
98 pageNumber
, matchMode
, false);
99 List
<T
> result
= (List
<T
>)query
.list();
104 public Long
countTitleCache(Class
<?
extends T
> clazz
, String queryString
, MatchMode matchMode
){
106 Query query
= prepareFindTitleCache(clazz
, queryString
, null,
107 null, matchMode
, true);
108 Long result
= (Long
)query
.uniqueResult();
113 * @param clazz filter by class - can be null to include all instances of type T
114 * @param queryString the query string to filter by
117 * @param matchmode use a particular type of matching (can be null - defaults to exact matching)
120 private Query
prepareFindTitleCache(Class
<?
extends T
> clazz
,
121 String queryString
, Integer pageSize
, Integer pageNumber
,
122 MatchMode matchMode
, boolean doCount
) {
127 String what
= (doCount ?
"count(distinct e.titleCache)": "distinct e.titleCache");
129 if(matchMode
!= null){
130 queryString
= matchMode
.queryStringFrom(queryString
);
132 String hql
= "select " + what
+ " from " + clazz
.getName() + " e where e.titleCache like '" + queryString
+ "'";
134 Query query
= getSession().createQuery(hql
);
136 if(pageSize
!= null && !doCount
) {
137 query
.setMaxResults(pageSize
);
138 if(pageNumber
!= null) {
139 query
.setFirstResult(pageNumber
* pageSize
);
146 public List
<T
> findByTitle(Class
<?
extends T
> clazz
, String queryString
, MatchMode matchmode
, List
<Criterion
> criterion
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
147 return findByParam(clazz
, "titleCache", queryString
, matchmode
, criterion
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
150 public List
<T
> findByReferenceTitle(Class
<?
extends T
> clazz
, String queryString
, MatchMode matchmode
, List
<Criterion
> criterion
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
151 return findByParam(clazz
, "title", queryString
, matchmode
, criterion
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
155 * @see eu.etaxonomy.cdm.persistence.dao.common.ITitledDao#findByTitle(java.lang.String, boolean, int, int, java.util.List)
157 public List
<T
> findByTitle(String queryString
, MatchMode matchmode
, int page
, int pagesize
, List
<Criterion
> criteria
) {
158 checkNotInPriorView("IdentifiableDaoBase.findByTitle(String queryString, MATCH_MODE matchmode, int page, int pagesize, List<Criterion> criteria)");
159 Criteria crit
= getSession().createCriteria(type
);
160 if (matchmode
== MatchMode
.EXACT
) {
161 crit
.add(Restrictions
.eq("titleCache", matchmode
.queryStringFrom(queryString
)));
163 // crit.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString)));
164 crit
.add(Restrictions
.like("titleCache", matchmode
.queryStringFrom(queryString
)));
167 crit
.setMaxResults(pagesize
);
169 if(criteria
!= null){
170 for (Criterion criterion
: criteria
) {
174 crit
.addOrder(Order
.asc("titleCache"));
175 int firstItem
= (page
- 1) * pagesize
;
176 crit
.setFirstResult(firstItem
);
177 List
<T
> results
= crit
.list();
178 List
<String
> propertyPaths
= null;
179 defaultBeanInitializer
.initializeAll(results
, propertyPaths
);
183 public int countRights(T identifiableEntity
) {
184 checkNotInPriorView("IdentifiableDaoBase.countRights(T identifiableEntity)");
185 Query query
= getSession().createQuery("select count(rights) from " + type
.getSimpleName() + " identifiableEntity join identifiableEntity.rights rights where identifiableEntity = :identifiableEntity");
186 query
.setParameter("identifiableEntity",identifiableEntity
);
187 return ((Long
)query
.uniqueResult()).intValue();
190 public int countSources(T identifiableEntity
) {
191 checkNotInPriorView("IdentifiableDaoBase.countSources(T identifiableEntity)");
192 Query query
= getSession().createQuery("select count(source) from OriginalSourceBase source where source.sourcedObj = :identifiableEntity");
193 query
.setParameter("identifiableEntity",identifiableEntity
);
194 return ((Long
)query
.uniqueResult()).intValue();
197 public List
<Rights
> getRights(T identifiableEntity
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
198 checkNotInPriorView("IdentifiableDaoBase.getRights(T identifiableEntity, Integer pageSize, Integer pageNumber, List<String> propertyPaths)");
199 Query query
= getSession().createQuery("select rights from " + type
.getSimpleName() + " identifiableEntity join identifiableEntity.rights rights where identifiableEntity = :identifiableEntity");
200 query
.setParameter("identifiableEntity",identifiableEntity
);
201 setPagingParameter(query
, pageSize
, pageNumber
);
202 List
<Rights
> results
= (List
<Rights
>)query
.list();
203 defaultBeanInitializer
.initializeAll(results
, propertyPaths
);
207 public List
<Credit
> getCredits(T identifiableEntity
, Integer pageSize
, Integer pageNumber
) {
208 checkNotInPriorView("IdentifiableDaoBase.getCredits(T identifiableEntity, Integer pageSize, Integer pageNumber)");
209 Query query
= getSession().createQuery("select credits from " + type
.getSimpleName() + " identifiableEntity join identifiableEntity.credits credits where identifiableEntity = :identifiableEntity");
210 query
.setParameter("identifiableEntity",identifiableEntity
);
211 setPagingParameter(query
, pageSize
, pageNumber
);
212 return (List
<Credit
>)query
.list();
215 public List
<IdentifiableSource
> getSources(T identifiableEntity
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
216 checkNotInPriorView("IdentifiableDaoBase.getSources(T identifiableEntity, Integer pageSize, Integer pageNumber)");
217 Query query
= getSession().createQuery("select source from OriginalSourceBase source where source.sourcedObj.id = :id and source.sourcedObj.class = :class");
218 query
.setParameter("id",identifiableEntity
.getId());
219 query
.setParameter("class",identifiableEntity
.getClass().getName());
220 setPagingParameter(query
, pageSize
, pageNumber
);
221 List
<IdentifiableSource
> results
= (List
<IdentifiableSource
>)query
.list();
222 defaultBeanInitializer
.initializeAll(results
, propertyPaths
);
226 public List
<T
> findOriginalSourceByIdInSource(String idInSource
, String idNamespace
) {
227 checkNotInPriorView("IdentifiableDaoBase.findOriginalSourceByIdInSource(String idInSource, String idNamespace)");
228 Query query
= getSession().createQuery(
229 "Select c from " + type
.getSimpleName() + " as c " +
230 "inner join c.sources as source " +
231 "where source.idInSource = :idInSource " +
232 " AND source.idNamespace = :idNamespace"
234 query
.setString("idInSource", idInSource
);
235 query
.setString("idNamespace", idNamespace
);
236 //TODO integrate reference in where
237 return (List
<T
>)query
.list();
240 public T
find(LSID lsid
) {
241 checkNotInPriorView("IdentifiableDaoBase.find(LSID lsid)");
242 Criteria criteria
= getSession().createCriteria(type
);
243 criteria
.add(Restrictions
.eq("lsid.authority", lsid
.getAuthority()));
244 criteria
.add(Restrictions
.eq("lsid.namespace", lsid
.getNamespace()));
245 criteria
.add(Restrictions
.eq("lsid.object", lsid
.getObject()));
247 if(lsid
.getRevision() != null) {
248 criteria
.add(Restrictions
.eq("lsid.revision", lsid
.getRevision()));
251 T object
= (T
)criteria
.uniqueResult();
255 AuditQuery query
= getAuditReader().createQuery().forRevisionsOfEntity(type
, false, true);
256 query
.add(AuditEntity
.property("lsid_authority").eq(lsid
.getAuthority()));
257 query
.add(AuditEntity
.property("lsid_namespace").eq(lsid
.getNamespace()));
258 query
.add(AuditEntity
.property("lsid_object").eq(lsid
.getObject()));
260 if(lsid
.getRevision() != null) {
261 query
.add(AuditEntity
.property("lsid_revision").eq(lsid
.getRevision()));
264 query
.addOrder(AuditEntity
.revisionNumber().asc());
265 query
.setMaxResults(1);
266 query
.setFirstResult(0);
267 List
<Object
[]> objs
= (List
<Object
[]>)query
.getResultList();
271 return (T
)objs
.get(0)[0];
276 public List
<UuidAndTitleCache
<T
>> getUuidAndTitleCache(){
277 Session session
= getSession();
278 Query query
= session
.createQuery("select uuid, titleCache from " + type
.getSimpleName());
279 return getUuidAndTitleCache(query
);
282 protected <E
extends IIdentifiableEntity
> List
<UuidAndTitleCache
<E
>> getUuidAndTitleCache(Query query
){
283 List
<UuidAndTitleCache
<E
>> list
= new ArrayList
<UuidAndTitleCache
<E
>>();
285 List
<Object
[]> result
= query
.list();
287 for(Object
[] object
: result
){
288 list
.add(new UuidAndTitleCache
<E
>((UUID
) object
[0], (String
) object
[1]));
295 public int countByTitle(Class
<?
extends T
> clazz
, String queryString
, MatchMode matchmode
, List
<Criterion
> criterion
) {
296 return countByParam(clazz
, "titleCache",queryString
,matchmode
,criterion
);
299 public int countByReferenceTitle(Class
<?
extends T
> clazz
, String queryString
, MatchMode matchmode
, List
<Criterion
> criterion
) {
300 return countByParam(clazz
, "title",queryString
,matchmode
,criterion
);
303 public int count(Class
<?
extends T
> clazz
, String queryString
) {
304 checkNotInPriorView("IdentifiableDaoBase.count(Class<? extends T> clazz, String queryString)");
305 QueryParser queryParser
= new QueryParser(version
, defaultField
, new StandardAnalyzer(version
));
308 org
.apache
.lucene
.search
.Query query
= queryParser
.parse(queryString
);
310 FullTextSession fullTextSession
= Search
.getFullTextSession(this.getSession());
311 org
.hibernate
.search
.FullTextQuery fullTextQuery
= null;
314 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, type
);
316 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, clazz
);
319 Integer result
= fullTextQuery
.getResultSize();
322 } catch (ParseException e
) {
323 throw new QueryParseException(e
, queryString
);
327 public void optimizeIndex() {
328 FullTextSession fullTextSession
= Search
.getFullTextSession(getSession());
329 SearchFactory searchFactory
= fullTextSession
.getSearchFactory();
330 for(Class clazz
: indexedClasses
) {
331 searchFactory
.optimize(clazz
); // optimize the indices ()
333 fullTextSession
.flushToIndexes();
336 public void purgeIndex() {
337 FullTextSession fullTextSession
= Search
.getFullTextSession(getSession());
338 for(Class clazz
: indexedClasses
) {
339 fullTextSession
.purgeAll(clazz
); // remove all objects of type t from indexes
341 fullTextSession
.flushToIndexes();
344 public void rebuildIndex() {
345 FullTextSession fullTextSession
= Search
.getFullTextSession(getSession());
347 for(T t
: list(null,null)) { // re-index all objects
348 fullTextSession
.index(t
);
350 fullTextSession
.flushToIndexes();
353 public List
<T
> search(Class
<?
extends T
> clazz
, String queryString
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,List
<String
> propertyPaths
) {
354 checkNotInPriorView("IdentifiableDaoBase.search(Class<? extends T> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,List<String> propertyPaths)");
355 QueryParser queryParser
= new QueryParser(version
, defaultField
, new StandardAnalyzer(version
));
356 List
<T
> results
= new ArrayList
<T
>();
359 org
.apache
.lucene
.search
.Query query
= queryParser
.parse(queryString
);
361 FullTextSession fullTextSession
= Search
.getFullTextSession(getSession());
362 org
.hibernate
.search
.FullTextQuery fullTextQuery
= null;
365 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, type
);
367 fullTextQuery
= fullTextSession
.createFullTextQuery(query
, clazz
);
370 addOrder(fullTextQuery
,orderHints
);
372 if(pageSize
!= null) {
373 fullTextQuery
.setMaxResults(pageSize
);
374 if(pageNumber
!= null) {
375 fullTextQuery
.setFirstResult(pageNumber
* pageSize
);
377 fullTextQuery
.setFirstResult(0);
381 List
<T
> result
= (List
<T
>)fullTextQuery
.list();
382 defaultBeanInitializer
.initializeAll(result
, propertyPaths
);
385 } catch (ParseException e
) {
386 throw new QueryParseException(e
, queryString
);
390 public String
suggestQuery(String string
) {
391 throw new UnsupportedOperationException("suggestQuery is not supported for objects of class " + type
.getName());
395 public Integer
countByTitle(String queryString
) {
396 return countByTitle(queryString
, null);
400 public Integer
countByTitle(String queryString
, CdmBase sessionObject
) {
401 Session session
= getSession();
402 if ( sessionObject
!= null ) {
403 session
.update(sessionObject
);
405 checkNotInPriorView("IdentifiableDaoBase.countByTitle(String queryString, CdmBase sessionObject)");
406 Criteria crit
= session
.createCriteria(type
);
407 crit
.add(Restrictions
.ilike("titleCache", queryString
));
408 Integer result
= ((Number
)crit
.setProjection(Projections
.rowCount()).uniqueResult()).intValue();
413 public Integer
countByTitle(String queryString
, MatchMode matchMode
, List
<Criterion
> criteria
) {
414 checkNotInPriorView("IdentifiableDaoBase.findByTitle(String queryString, MATCH_MODE matchmode, int page, int pagesize, List<Criterion> criteria)");
415 Criteria crit
= getSession().createCriteria(type
);
416 if (matchMode
== MatchMode
.EXACT
) {
417 crit
.add(Restrictions
.eq("titleCache", matchMode
.queryStringFrom(queryString
)));
419 // crit.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString)));
420 crit
.add(Restrictions
.like("titleCache", matchMode
.queryStringFrom(queryString
)));
423 if(criteria
!= null){
424 for (Criterion criterion
: criteria
) {
430 Integer result
= ((Number
)crit
.setProjection(Projections
.rowCount()).uniqueResult()).intValue();