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
.term
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Collection
;
13 import java
.util
.Collections
;
14 import java
.util
.HashSet
;
15 import java
.util
.List
;
18 import java
.util
.UUID
;
20 import org
.hibernate
.Criteria
;
21 import org
.hibernate
.Query
;
22 import org
.hibernate
.Session
;
23 import org
.hibernate
.criterion
.CriteriaSpecification
;
24 import org
.hibernate
.criterion
.Restrictions
;
25 import org
.hibernate
.envers
.query
.AuditEntity
;
26 import org
.hibernate
.envers
.query
.AuditQuery
;
27 import org
.springframework
.stereotype
.Repository
;
29 import eu
.etaxonomy
.cdm
.model
.common
.CdmClass
;
30 import eu
.etaxonomy
.cdm
.model
.term
.DefinedTermBase
;
31 import eu
.etaxonomy
.cdm
.model
.term
.OrderedTermVocabulary
;
32 import eu
.etaxonomy
.cdm
.model
.term
.TermType
;
33 import eu
.etaxonomy
.cdm
.model
.term
.TermVocabulary
;
34 import eu
.etaxonomy
.cdm
.model
.view
.AuditEvent
;
35 import eu
.etaxonomy
.cdm
.persistence
.dao
.hibernate
.common
.IdentifiableDaoBase
;
36 import eu
.etaxonomy
.cdm
.persistence
.dao
.term
.ITermVocabularyDao
;
37 import eu
.etaxonomy
.cdm
.persistence
.dto
.FeatureDto
;
38 import eu
.etaxonomy
.cdm
.persistence
.dto
.TermCollectionDto
;
39 import eu
.etaxonomy
.cdm
.persistence
.dto
.TermDto
;
40 import eu
.etaxonomy
.cdm
.persistence
.dto
.TermVocabularyDto
;
41 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
42 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
48 public class TermVocabularyDaoImpl
extends IdentifiableDaoBase
<TermVocabulary
> implements
51 @SuppressWarnings("unchecked")
52 public TermVocabularyDaoImpl() {
53 super(TermVocabulary
.class);
54 indexedClasses
= new Class
[2];
55 indexedClasses
[0] = TermVocabulary
.class;
56 indexedClasses
[1] = OrderedTermVocabulary
.class;
60 public long countTerms(TermVocabulary termVocabulary
) {
61 AuditEvent auditEvent
= getAuditEventFromContext();
62 if(auditEvent
.equals(AuditEvent
.CURRENT_VIEW
)) {
63 Query query
= getSession().createQuery("select count(term) from DefinedTermBase term where term.vocabulary = :vocabulary");
64 query
.setParameter("vocabulary", termVocabulary
);
66 return (Long
)query
.uniqueResult();
68 AuditQuery query
= makeAuditQuery(null, auditEvent
);
69 query
.addProjection(AuditEntity
.id().count());
70 query
.add(AuditEntity
.relatedId("vocabulary").eq(termVocabulary
.getId()));
71 return (Long
)query
.getSingleResult();
76 public <T
extends DefinedTermBase
> List
<T
> getTerms(TermVocabulary
<T
> vocabulary
,Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,List
<String
> propertyPaths
) {
77 AuditEvent auditEvent
= getAuditEventFromContext();
78 if(auditEvent
.equals(AuditEvent
.CURRENT_VIEW
)) {
79 Criteria criteria
= getCriteria(DefinedTermBase
.class);
80 criteria
.createCriteria("vocabulary").add(Restrictions
.idEq(vocabulary
.getId()));
82 addPageSizeAndNumber(criteria
, pageSize
, pageNumber
);
83 this.addOrder(criteria
, orderHints
);
85 @SuppressWarnings("unchecked")
86 List
<T
> result
= DefinedTermDaoImpl
.deduplicateResult(criteria
.list());
87 defaultBeanInitializer
.initializeAll(result
, propertyPaths
);
90 AuditQuery query
= makeAuditQuery(null, auditEvent
);
91 query
.add(AuditEntity
.relatedId("vocabulary").eq(vocabulary
.getId()));
93 addPageSizeAndNumber(query
, pageSize
, pageNumber
);
95 @SuppressWarnings("unchecked")
96 List
<T
> result
= DefinedTermDaoImpl
.deduplicateResult(query
.getResultList());
97 defaultBeanInitializer
.initializeAll(result
, propertyPaths
);
103 public <T
extends DefinedTermBase
> TermVocabulary
<T
> findByUri(String termSourceUri
, Class
<T
> clazz
) {
104 AuditEvent auditEvent
= getAuditEventFromContext();
105 if(auditEvent
.equals(AuditEvent
.CURRENT_VIEW
)) {
107 Query query
= getSession().createQuery("select vocabulary from TermVocabulary vocabulary where vocabulary.termSourceUri= :termSourceUri");
108 query
.setParameter("termSourceUri", termSourceUri
);
110 @SuppressWarnings("unchecked")
111 TermVocabulary
<T
> result
= (TermVocabulary
<T
>)query
.uniqueResult();
114 AuditQuery query
= makeAuditQuery(clazz
, auditEvent
);
115 query
.add(AuditEntity
.property("termSourceUri").eq(termSourceUri
));
117 @SuppressWarnings("unchecked")
118 TermVocabulary
<T
> result
= (TermVocabulary
<T
>)query
.getSingleResult();
124 public <T
extends DefinedTermBase
> List
<T
> getTerms(TermVocabulary
<T
> termVocabulary
, Integer pageSize
, Integer pageNumber
) {
125 return getTerms(termVocabulary
, pageSize
, pageNumber
, null, null);
129 public <T
extends DefinedTermBase
> List
<TermVocabulary
<T
>> findByTermType(TermType termType
, List
<String
> propertyPaths
) {
131 Criteria criteria
= getSession().createCriteria(type
);
132 criteria
.add(Restrictions
.eq("termType", termType
));
133 criteria
.setResultTransformer(CriteriaSpecification
.DISTINCT_ROOT_ENTITY
);
134 //this.addOrder(criteria, orderHints);
136 @SuppressWarnings("unchecked")
137 List
<TermVocabulary
<T
>> result
= DefinedTermDaoImpl
.deduplicateResult(criteria
.list());
138 defaultBeanInitializer
.initializeAll(result
, propertyPaths
);
143 public List
<TermVocabulary
> listByTermType(TermType termType
, boolean includeSubTypes
, Integer limit
, Integer start
,List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
144 checkNotInPriorView("TermVocabularyDao.listByTermType(TermType termType, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths)");
146 Set
<TermType
> allTermTypes
= new HashSet
<TermType
>();
147 allTermTypes
.add(termType
);
148 if (includeSubTypes
){
149 allTermTypes
.addAll(termType
.getGeneralizationOf(true));
152 Criteria criteria
= getSession().createCriteria(type
);
153 criteria
.add(Restrictions
.in("termType", allTermTypes
));
156 criteria
.setMaxResults(limit
);
158 criteria
.setFirstResult(start
);
162 this.addOrder(criteria
, orderHints
);
164 @SuppressWarnings("unchecked")
165 List
<TermVocabulary
> result
= DefinedTermDaoImpl
.deduplicateResult(criteria
.list());
166 defaultBeanInitializer
.initializeAll(result
, propertyPaths
);
171 public void missingTermUuids(
172 Map
<UUID
, Set
<UUID
>> uuidsRequested
,
173 Map
<UUID
, Set
<UUID
>> uuidMissingTermsRepsonse
,
174 Map
<UUID
, TermVocabulary
<?
>> vocabularyResponse
){
176 Set
<UUID
> missingTermCandidateUuids
= new HashSet
<>();
178 for (Set
<UUID
> uuidsPerVocSet
: uuidsRequested
.values()){
179 missingTermCandidateUuids
.addAll(uuidsPerVocSet
);
182 //search persisted subset of required (usually all)
183 String hql
= " SELECT terms.uuid " +
184 " FROM TermVocabulary voc join voc.terms terms " +
185 " WHERE terms.uuid IN (:uuids) " +
186 " ORDER BY voc.uuid ";
187 Query query
= getSession().createQuery(hql
);
189 int splitSize
= 2000;
190 List
<Collection
<UUID
>> missingTermCandidates
= splitCollection(missingTermCandidateUuids
, splitSize
);
191 List
<UUID
> persistedUuids
= new ArrayList
<>();
193 for (Collection
<UUID
> uuids
: missingTermCandidates
){
194 query
.setParameterList("uuids", uuids
);
195 @SuppressWarnings("unchecked")
196 List
<UUID
> list
= query
.list();
197 persistedUuids
.addAll(list
);
201 //fully load and initialize vocabularies if required
202 if (vocabularyResponse
!= null){
203 String hql2
= " SELECT DISTINCT voc " +
204 " FROM TermVocabulary voc " +
205 " LEFT JOIN FETCH voc.terms terms " +
206 " LEFT JOIN FETCH terms.representations representations " +
207 " LEFT JOIN FETCH voc.representations vocReps " +
208 " WHERE terms.uuid IN (:termUuids) OR ( voc.uuid IN (:vocUuids) ) " + //was: AND voc.terms is empty, but did not load originally empty vocabularies with user defined terms added
209 // " WHERE voc.uuid IN (:vocUuids) AND voc.terms is empty " +
210 " ORDER BY voc.uuid ";
211 query
= getSession().createQuery(hql2
);
212 query
.setParameterList("termUuids", missingTermCandidateUuids
);
213 query
.setParameterList("vocUuids", uuidsRequested
.keySet());
215 for (Collection
<UUID
> uuids
: missingTermCandidates
){
216 query
.setParameterList("termUuids", uuids
);
217 @SuppressWarnings("unchecked")
218 List
<TermVocabulary
<?
>> o
= query
.list();
219 for (TermVocabulary
<?
> voc
: o
){
220 vocabularyResponse
.put(voc
.getUuid(), voc
);
225 //compute missing terms
226 if (missingTermCandidateUuids
.size() == persistedUuids
.size()){
227 missingTermCandidateUuids
.clear();
229 missingTermCandidateUuids
.removeAll(persistedUuids
);
230 //add missing terms to response
231 for (UUID vocUUID
: uuidsRequested
.keySet()){
232 for (UUID termUuid
: uuidsRequested
.get(vocUUID
)){
233 if (missingTermCandidateUuids
.contains(termUuid
)){
234 Set
<UUID
> r
= uuidMissingTermsRepsonse
.get(vocUUID
);
237 uuidMissingTermsRepsonse
.put(vocUUID
, r
);
249 public Collection
<TermDto
> getTerms(List
<UUID
> vocabularyUuids
) {
250 String queryString
= TermDto
.getTermDtoSelect()
251 + "where v.uuid in :vocabularyUuids "
252 + "order by a.titleCache";
253 Query query
= getSession().createQuery(queryString
);
254 query
.setParameterList("vocabularyUuids", vocabularyUuids
);
256 @SuppressWarnings("unchecked")
257 List
<Object
[]> result
= DefinedTermDaoImpl
.deduplicateResult(query
.list());
259 List
<TermDto
> list
= TermDto
.termDtoListFrom(result
);
264 public Collection
<TermDto
> getTerms(UUID vocabularyUuid
) {
265 String queryString
= TermDto
.getTermDtoSelect()
266 + "where v.uuid = :vocabularyUuid "
267 + "order by a.titleCache";
268 Query query
= getSession().createQuery(queryString
);
269 query
.setParameter("vocabularyUuid", vocabularyUuid
);
271 @SuppressWarnings("unchecked")
272 List
<Object
[]> result
= DefinedTermDaoImpl
.deduplicateResult(query
.list());
274 List
<TermDto
> list
= TermDto
.termDtoListFrom(result
);
279 public Collection
<TermDto
> getNamedAreaTerms(List
<UUID
> vocabularyUuids
) {
280 String queryString
= TermDto
.getTermDtoSelectNamedArea()
281 + "where v.uuid in :vocabularyUuids "
282 + "order by a.titleCache";
283 Query query
= getSession().createQuery(queryString
);
284 query
.setParameterList("vocabularyUuids", vocabularyUuids
);
286 @SuppressWarnings("unchecked")
287 List
<Object
[]> result
= DefinedTermDaoImpl
.deduplicateResult(query
.list());
289 List
<TermDto
> list
= TermDto
.termDtoListFrom(result
);
294 public Collection
<TermDto
> getTopLevelTerms(UUID vocabularyUuid
) {
295 String queryString
= TermDto
.getTermDtoSelect()
296 + "where v.uuid = :vocabularyUuid "
297 + "and a.partOf is null "
298 + "and a.kindOf is null";
299 Query query
= getSession().createQuery(queryString
);
300 query
.setParameter("vocabularyUuid", vocabularyUuid
);
302 @SuppressWarnings("unchecked")
303 List
<Object
[]> result
= DefinedTermDaoImpl
.deduplicateResult(query
.list());
305 List
<TermDto
> list
= TermDto
.termDtoListFrom(result
);
310 public Collection
<TermDto
> getTopLevelTerms(UUID vocabularyUuid
, TermType type
) {
312 if (type
.equals(TermType
.NamedArea
)){
313 queryString
= TermDto
.getTermDtoSelectNamedArea();
314 }else if (type
.equals(TermType
.Feature
) || type
.isKindOf(TermType
.Feature
)){
315 queryString
= FeatureDto
.getTermDtoSelect();
317 queryString
= TermDto
.getTermDtoSelect();
319 queryString
= queryString
320 + "where v.uuid = :vocabularyUuid "
321 + "and a.partOf is null "
322 + "and a.kindOf is null";
323 Query query
= getSession().createQuery(queryString
);
324 query
.setParameter("vocabularyUuid", vocabularyUuid
);
326 @SuppressWarnings("unchecked")
327 List
<Object
[]> result
= DefinedTermDaoImpl
.deduplicateResult(query
.list());
328 List
<TermDto
> list
= null;
329 if (type
.equals(TermType
.Feature
)|| type
.isKindOf(TermType
.Feature
)){
330 list
= FeatureDto
.termDtoListFrom(result
);
332 list
= TermDto
.termDtoListFrom(result
);
338 public List
<TermVocabularyDto
> findVocabularyDtoByTermTypes(Set
<TermType
> termTypes
) {
339 return findVocabularyDtoByTermTypes(termTypes
, true);
343 public List
<TermVocabularyDto
> findVocabularyDtoByTermTypes(Set
<TermType
> termTypes
, boolean includeSubtypes
) {
344 return findVocabularyDtoByTermTypes(termTypes
, null, includeSubtypes
);
348 public List
<TermVocabularyDto
> findVocabularyDtoByAvailableFor(Set
<CdmClass
> availableForSet
) {
350 String queryVocWithFittingTerms
= "SELECT DISTINCT(v.uuid) FROM DefinedTermBase term JOIN term.vocabulary as v WHERE " ;
351 for (CdmClass availableFor
: availableForSet
){
352 queryVocWithFittingTerms
+= " term.availableFor like '%"+availableFor
.getKey()+"%' AND term.termType = :feature";
356 // Query query1 = getSession().createQuery(queryVocWithFittingTerms);
357 // List<Object[]> result1 = query1.list();
359 String queryString
= TermCollectionDto
.getTermCollectionDtoSelect()
360 + " WHERE a.uuid in "
361 + " (" + queryVocWithFittingTerms
+ ")";
366 Query query
= getSession().createQuery(queryString
);
367 query
.setParameter("feature", TermType
.Feature
);
369 @SuppressWarnings("unchecked")
370 List
<Object
[]> result
= DefinedTermDaoImpl
.deduplicateResult(query
.list());
372 // Map<UUID, TermVocabularyDto> dtoMap = new HashMap<>(result.size());
373 List
<TermVocabularyDto
> dtos
= TermVocabularyDto
.termVocabularyDtoListFrom(result
);
380 public List
<TermVocabularyDto
> findVocabularyDtoByTermTypes(Set
<TermType
> termTypes
, String pattern
, boolean includeSubtypes
) {
381 Set
<TermType
> termTypeWithSubType
= new HashSet
<>();
382 if (! (termTypes
.isEmpty() || (termTypes
.size() == 1 && termTypes
.iterator().next() == null))){
383 termTypeWithSubType
= new HashSet
<>(termTypes
);
387 if (!termTypes
.isEmpty()){
388 for (TermType termType
: termTypes
) {
389 if (termType
!= null){
390 termTypeWithSubType
.addAll(termType
.getGeneralizationOf(true));
395 String queryString
= TermVocabularyDto
.getTermCollectionDtoSelect();
397 if (!termTypeWithSubType
.isEmpty()){
398 queryString
+= " where a.termType in (:termTypes) ";
399 if (pattern
!= null){
400 queryString
+= " AND a.titleCache like :pattern";
403 if (pattern
!= null){
404 queryString
+= " WHERE a.titleCache like :pattern";
408 Query query
= getSession().createQuery(queryString
);
409 if (!termTypeWithSubType
.isEmpty()){
410 query
.setParameterList("termTypes", termTypeWithSubType
);
412 if (pattern
!= null){
413 pattern
= pattern
.replace("*", "%");
414 pattern
= "%"+pattern
+"%";
415 query
.setParameter("pattern", pattern
);
417 @SuppressWarnings("unchecked")
418 List
<Object
[]> result
= DefinedTermDaoImpl
.deduplicateResult(query
.list());
419 List
<TermVocabularyDto
> dtos
= TermVocabularyDto
.termVocabularyDtoListFrom(result
);
422 // Map<UUID, TermVocabularyDto> dtoMap = new HashMap<>(result.size());
423 // for (Object[] elements : result) {
424 // UUID uuid = (UUID)elements[0];
425 // TermType termType = (TermType)elements[1];
426 // if(dtoMap.containsKey(uuid)){
427 // dtoMap.get(uuid).addRepresentation((Representation)elements[2]);
429 // Set<Representation> representations = new HashSet<>();
430 // if(elements[2] instanceof Representation) {
431 // representations = new HashSet<Representation>();
432 // representations.add((Representation)elements[2]);
434 // representations = (Set<Representation>)elements[2];
436 // dtoMap.put(uuid, new TermVocabularyDto(uuid, representations, termType, (String)elements[3]));
439 // return new ArrayList<>(dtoMap.values());
443 public List
<TermVocabularyDto
> findVocabularyDtoByTermType(TermType termType
) {
444 return findVocabularyDtoByTermTypes(Collections
.singleton(termType
));
448 public <S
extends TermVocabulary
> List
<UuidAndTitleCache
<S
>> getUuidAndTitleCache(Class
<S
> clazz
, TermType termType
,
449 Integer limit
, String pattern
) {
451 return getUuidAndTitleCache(clazz
, limit
, pattern
);
453 Session session
= getSession();
455 if (pattern
!= null){
456 query
= session
.createQuery(
457 " SELECT uuid, id, titleCache "
458 + " FROM " + clazz
.getSimpleName()
459 + " WHERE titleCache LIKE :pattern "
460 + " AND termType = :termType");
461 pattern
= pattern
.replace("*", "%");
462 pattern
= pattern
.replace("?", "_");
463 pattern
= pattern
+ "%";
464 query
.setParameter("pattern", pattern
);
466 query
= session
.createQuery(
467 " SELECT uuid, id, titleCache "
468 + " FROM " + clazz
.getSimpleName()
469 + " WHERE termType = :termType");
471 query
.setParameter("termType", termType
);
473 query
.setMaxResults(limit
);
475 return getUuidAndTitleCache(query
);
479 public TermVocabularyDto
findVocabularyDtoByUuid(UUID vocUuid
) {
480 if (vocUuid
== null ){
484 String queryString
= TermCollectionDto
.getTermCollectionDtoSelect()
485 + " where a.uuid like :uuid ";
486 // + "order by a.titleCache";
487 Query query
= getSession().createQuery(queryString
);
488 query
.setParameter("uuid", vocUuid
);
490 @SuppressWarnings("unchecked")
491 List
<Object
[]> result
= DefinedTermDaoImpl
.deduplicateResult(query
.list());
492 if (result
.size() == 1){
493 return TermVocabularyDto
.termVocabularyDtoListFrom(result
).get(0);
499 public List
<TermVocabularyDto
> findVocabularyDtoByUuids(List
<UUID
> vocUuids
) {
501 if (vocUuids
== null || vocUuids
.isEmpty()){
504 List
<TermVocabularyDto
> list
= new ArrayList
<>();
506 String queryString
= TermCollectionDto
.getTermCollectionDtoSelect()
507 + "where a.uuid in :uuidList ";
508 // + "order by a.titleCache";
509 Query query
= getSession().createQuery(queryString
);
510 query
.setParameterList("uuidList", vocUuids
);
512 @SuppressWarnings("unchecked")
513 List
<Object
[]> result
= DefinedTermDaoImpl
.deduplicateResult(query
.list());
515 list
= TermVocabularyDto
.termVocabularyDtoListFrom(result
);