2 * Copyright (C) 2017 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
.name
;
11 import java
.util
.Collection
;
12 import java
.util
.Collections
;
13 import java
.util
.HashMap
;
14 import java
.util
.List
;
16 import java
.util
.Optional
;
17 import java
.util
.UUID
;
19 import org
.apache
.commons
.lang3
.StringUtils
;
20 import org
.apache
.logging
.log4j
.LogManager
;
21 import org
.apache
.logging
.log4j
.Logger
;
22 import org
.hibernate
.query
.Query
;
23 import org
.springframework
.stereotype
.Repository
;
25 import eu
.etaxonomy
.cdm
.model
.name
.Registration
;
26 import eu
.etaxonomy
.cdm
.model
.name
.RegistrationStatus
;
27 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
28 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceType
;
29 import eu
.etaxonomy
.cdm
.persistence
.dao
.hibernate
.common
.AnnotatableDaoBaseImpl
;
30 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.IRegistrationDao
;
31 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
32 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
35 * @author a.kohlbecker
39 public class RegistrationDaoHibernateImpl
40 extends AnnotatableDaoBaseImpl
<Registration
>
41 implements IRegistrationDao
{
43 @SuppressWarnings("unused")
44 private static final Logger logger
= LogManager
.getLogger();
46 public RegistrationDaoHibernateImpl() {
47 super(Registration
.class);
51 public Long
count(Optional
<Reference
> reference
, Collection
<RegistrationStatus
> includedStatus
) {
52 //return 0 for detached volatile references
53 if (isVolatile(reference
)){
54 return Long
.valueOf(0);
56 Query
<Long
> query
= makeReferenceQuery(reference
, includedStatus
, true, Long
.class);
57 List
<Long
> list
= query
.list();
58 return list
.isEmpty()? Long
.valueOf(0) : list
.get(0);
62 public List
<Registration
> list(Optional
<Reference
> reference
, Collection
<RegistrationStatus
> includedStatus
,
63 Integer limit
, Integer start
, List
<String
> propertyPaths
) {
65 if (isVolatile(reference
)){
66 return Collections
.emptyList();
69 Query
<Registration
> query
= makeReferenceQuery(reference
, includedStatus
, false, Registration
.class);
71 addLimitAndStart(query
, limit
, start
);
73 //TODO order hints do not work with queries
75 List
<Registration
> results
= query
.list();
76 defaultBeanInitializer
.initializeAll(results
, propertyPaths
);
81 private boolean isVolatile(Optional
<Reference
> reference
) {
82 return reference
!= null && reference
.isPresent() && reference
.get().getId() == 0;
85 private <R
extends Object
> Query
<R
> makeReferenceQuery(Optional
<Reference
> reference
,
86 Collection
<RegistrationStatus
> includedStatus
,
87 boolean isCount
, Class
<R
> returnClass
) {
89 String select
= "SELECT " + (isCount?
" count(DISTINCT r) as cn ": "DISTINCT r ");
90 String from
= " FROM Registration r LEFT JOIN r.typeDesignations desig "
91 + " LEFT JOIN r.name n ";
92 String where
= " WHERE (1=1) ";
93 String orderBy
= isCount ?
"" : " ORDER BY r.id ";
95 ReferenceType refTypeParameter
= null;
97 if (reference
== null){
99 }else if (reference
.isPresent()){
100 from
+= " LEFT JOIN n.nomenclaturalSource nomSource "
101 + " LEFT JOIN nomSource.citation nomRef "
102 + " LEFT JOIN desig.designationSource desigSource "
103 + " LEFT JOIN desigSource.citation desigRef ";
106 + " OR (nomRef.type =:refType AND nomRef.inReference =:ref) "
107 + " OR desigRef =:ref "
108 + " OR (desigRef.type =:refType AND desigRef.inReference =:ref)"
110 refTypeParameter
= ReferenceType
.Section
;
112 from
+= " LEFT JOIN n.nomenclaturalSource nomSource "
113 + " LEFT JOIN desig.designationSource desigSource ";
114 where
+= " AND ((r.name IS NULL AND size(r.typeDesignations) = 0 ) "
115 + " OR (n IS NOT NULL AND (nomSource.citation IS NULL)) "
116 + " OR (size(r.typeDesignations) > 0 AND (desigSource.citation IS NULL))"
120 boolean hasStatus
= includedStatus
!= null && !includedStatus
.isEmpty();
122 where
+= " AND r.status IN (:status) ";
125 String hql
= select
+ from
+ where
+ orderBy
;
126 Query
<R
> query
= getSession().createQuery(hql
, returnClass
);
127 if (reference
!= null && reference
.isPresent()){
128 query
.setParameter("ref", reference
.get());
130 if(refTypeParameter
!= null){
131 query
.setParameter("refType", refTypeParameter
);
134 query
.setParameterList("status", includedStatus
);
140 public long count(UUID submitterUuid
, Collection
<RegistrationStatus
> includedStatus
, String identifierFilterPattern
,
141 String taxonNameFilterPattern
, String referenceFilterPattern
, Collection
<UUID
> typeDesignationStatusUuids
) {
142 Query
<Long
> query
= makeFilteredSearchQuery(submitterUuid
, includedStatus
, identifierFilterPattern
,
143 taxonNameFilterPattern
, referenceFilterPattern
, typeDesignationStatusUuids
, true, null);
144 // LogUtils.setLevel("org.hibernate.SQL", Level.DEBUG);
145 List
<Long
> list
= query
.list();
146 // LogUtils.setLevel("org.hibernate.SQL", Level.WARN);
147 return list
.isEmpty()? Long
.valueOf(0) : list
.get(0);
151 public List
<Registration
> list(UUID submitterUuid
, Collection
<RegistrationStatus
> includedStatus
, String identifierFilterPattern
,
152 String taxonNameFilterPattern
, String referenceFilterPattern
, Collection
<UUID
> typeDesignationStatusUuids
, Integer limit
, Integer start
,
153 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
155 Query
<Registration
> query
= makeFilteredSearchQuery(submitterUuid
, includedStatus
, identifierFilterPattern
,
156 taxonNameFilterPattern
, referenceFilterPattern
, typeDesignationStatusUuids
, false, orderHints
);
158 if(limit
!= null /*&& !doCount*/) {
159 query
.setMaxResults(limit
);
161 query
.setFirstResult(start
);
165 List
<Registration
> results
= query
.list();
166 defaultBeanInitializer
.initializeAll(results
, propertyPaths
);
172 public List
<Registration
> list(UUID submitterUuid
, Collection
<RegistrationStatus
> includedStatus
, Collection
<UUID
> taxonNameUUIDs
,
173 Integer limit
, Integer start
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
175 Query query
= makeByNameUUIDQuery(submitterUuid
, includedStatus
, taxonNameUUIDs
, false, orderHints
);
177 if(limit
!= null /*&& !doCount*/) {
178 query
.setMaxResults(limit
);
180 query
.setFirstResult(start
);
184 // LogUtils.setLevel("org.hibernate.SQL", Level.DEBUG);
185 @SuppressWarnings("unchecked")
186 List
<Registration
> results
= query
.list();
187 // LogUtils.setLevel("org.hibernate.SQL", Level.WARN);
188 defaultBeanInitializer
.initializeAll(results
, propertyPaths
);
194 public long count(UUID submitterUuid
, Collection
<RegistrationStatus
> includedStatus
, Collection
<UUID
> taxonNameUUIDs
) {
195 Query query
= makeByNameUUIDQuery(submitterUuid
, includedStatus
, taxonNameUUIDs
, true, null);
196 // LogUtils.setLevel("org.hibernate.SQL", Level.DEBUG);
197 @SuppressWarnings("unchecked")
198 List
<Long
> list
= query
.list();
199 // LogUtils.setLevel("org.hibernate.SQL", Level.WARN);
200 return list
.isEmpty()? Long
.valueOf(0) : list
.get(0);
203 private Query
makeByNameUUIDQuery(UUID submitterUuid
, Collection
<RegistrationStatus
> includedStatus
,
204 Collection
<UUID
> taxonNameUUIDs
, boolean isCount
, List
<OrderHint
> orderHints
) {
206 Map
<String
, Object
> parameters
= new HashMap
<>();
208 String select
= "SELECT " + (isCount?
" count(DISTINCT r) as cn ": "DISTINCT r ");
209 String from
= " FROM Registration r "
210 + " LEFT JOIN r.typeDesignations desig "
211 + " LEFT JOIN r.name n "
212 + " LEFT JOIN desig.typifiedNames typifiedNames "
214 String where
= " WHERE (1=1) ";
217 orderBy
= orderByClause("r", orderHints
).toString();
220 if(submitterUuid
!= null){
221 from
+= " LEFT JOIN r.submitter submitter "; // without this join hibernate would make a cross join here
222 where
+= " AND submitter.uuid =:submitterUuid";
223 parameters
.put("submitterUuid", submitterUuid
);
225 if(includedStatus
!= null && includedStatus
.size() > 0) {
226 where
+= " AND r.status in (:includedStatus)";
227 parameters
.put("includedStatus", includedStatus
);
230 where
+= " AND (r.name.uuid in(:nameUUIDs) OR typifiedNames.uuid in(:nameUUIDs))";
231 parameters
.put("nameUUIDs", taxonNameUUIDs
);
234 String hql
= select
+ from
+ where
+ orderBy
;
235 Query query
= getSession().createQuery(hql
);
237 for(String paramName
: parameters
.keySet()){
238 Object value
= parameters
.get(paramName
);
239 if(value
instanceof Collection
){
240 query
.setParameterList(paramName
, (Collection
)value
);
242 query
.setParameter(paramName
, value
);
249 private Query
makeFilteredSearchQuery(UUID submitterUuid
, Collection
<RegistrationStatus
> includedStatus
,
250 String identifierFilterPattern
, String taxonNameFilterPattern
, String referenceFilterPattern
,
251 Collection
<UUID
> typeDesignationStatusUuids
, boolean isCount
, List
<OrderHint
> orderHints
) {
253 Map
<String
, Object
> parameters
= new HashMap
<>();
255 boolean doNameFilter
= StringUtils
.isNoneBlank(taxonNameFilterPattern
);
256 boolean doReferenceFilter
= StringUtils
.isNoneBlank(referenceFilterPattern
);
257 boolean doTypeStatusFilter
= typeDesignationStatusUuids
!= null && typeDesignationStatusUuids
.size() > 0;
259 String select
= "SELECT " + (isCount?
" count(DISTINCT r) as cn ": "DISTINCT r ");
260 String from
= " FROM Registration r "
261 + " LEFT JOIN r.typeDesignations desig "
262 + " LEFT JOIN r.name n "
263 + (doNameFilter ?
" LEFT JOIN desig.typifiedNames typifiedNames ":"")
264 + (doTypeStatusFilter ?
" LEFT JOIN desig.typeStatus typeStatus":"") // without this join hibernate would make a cross join here
266 ?
" LEFT JOIN desig.designationSource typeDesignationSource "
267 + " LEFT JOIN typeDesignationSource.citation typeDesignationCitation "
268 + " LEFT JOIN n.nomenclaturalSource nomSource "
269 + " LEFT JOIN nomSource.citation nomRef "
273 String where
= " WHERE (1=1) ";
276 orderBy
= orderByClause("r", orderHints
).toString();
279 if(submitterUuid
!= null){
280 from
+= " LEFT JOIN r.submitter submitter "; // without this join hibernate would make a cross join here
281 where
+= " AND submitter.uuid =:submitterUuid";
282 parameters
.put("submitterUuid", submitterUuid
);
284 if(includedStatus
!= null && includedStatus
.size() > 0) {
285 where
+= " AND r.status in (:includedStatus)";
286 parameters
.put("includedStatus", includedStatus
);
288 if(StringUtils
.isNoneBlank(identifierFilterPattern
)){
289 where
+= " AND r.identifier LIKE :identifierFilterPattern";
290 parameters
.put("identifierFilterPattern", MatchMode
.ANYWHERE
.queryStringFrom(identifierFilterPattern
));
293 where
+= " AND (r.name.titleCache LIKE :taxonNameFilterPattern OR typifiedNames.titleCache LIKE :taxonNameFilterPattern)";
294 parameters
.put("taxonNameFilterPattern", MatchMode
.ANYWHERE
.queryStringFrom(taxonNameFilterPattern
));
296 if(doReferenceFilter
){
297 where
+= " AND (typeDesignationCitation.titleCache LIKE :referenceFilterPattern OR nomRef.titleCache LIKE :referenceFilterPattern)";
298 parameters
.put("referenceFilterPattern", MatchMode
.ANYWHERE
.queryStringFrom(referenceFilterPattern
));
300 if(doTypeStatusFilter
){
301 boolean addNullFilter
= false;
302 while(typeDesignationStatusUuids
.contains(null)){
303 addNullFilter
= true;
304 typeDesignationStatusUuids
.remove(null);
306 String typeStatusWhere
= "";
307 if(!typeDesignationStatusUuids
.isEmpty()){
308 typeStatusWhere
+= " typeStatus.uuid in (:typeDesignationStatusUuids)";
309 parameters
.put("typeDesignationStatusUuids", typeDesignationStatusUuids
);
312 typeStatusWhere
+= (!typeStatusWhere
.isEmpty() ?
" OR ":"") + "typeStatus is null";
314 where
+= " AND ( " + typeStatusWhere
+ ")";
316 String hql
= select
+ from
+ where
+ orderBy
;
317 Query query
= getSession().createQuery(hql
);
319 for(String paramName
: parameters
.keySet()){
320 Object value
= parameters
.get(paramName
);
321 if(value
instanceof Collection
){
322 query
.setParameterList(paramName
, (Collection
)value
);
324 query
.setParameter(paramName
, value
);