cleanup
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / name / RegistrationDaoHibernateImpl.java
1 /**
2 * Copyright (C) 2017 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.name;
10
11 import java.util.Collection;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Optional;
17 import java.util.UUID;
18
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;
24
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;
33
34 /**
35 * @author a.kohlbecker
36 * @since May 2, 2017
37 */
38 @Repository
39 public class RegistrationDaoHibernateImpl
40 extends AnnotatableDaoBaseImpl<Registration>
41 implements IRegistrationDao {
42
43 @SuppressWarnings("unused")
44 private static final Logger logger = LogManager.getLogger();
45
46 public RegistrationDaoHibernateImpl() {
47 super(Registration.class);
48 }
49
50 @Override
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);
55 }
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);
59 }
60
61 @Override
62 public List<Registration> list(Optional<Reference> reference, Collection<RegistrationStatus> includedStatus,
63 Integer limit, Integer start, List<String> propertyPaths) {
64
65 if (isVolatile(reference)){
66 return Collections.emptyList();
67 }
68
69 Query<Registration> query = makeReferenceQuery(reference, includedStatus, false, Registration.class);
70
71 addLimitAndStart(query, limit, start);
72
73 //TODO order hints do not work with queries
74
75 List<Registration> results = query.list();
76 defaultBeanInitializer.initializeAll(results, propertyPaths);
77
78 return results;
79 }
80
81 private boolean isVolatile(Optional<Reference> reference) {
82 return reference != null && reference.isPresent() && reference.get().getId() == 0;
83 }
84
85 private <R extends Object> Query<R> makeReferenceQuery(Optional<Reference> reference,
86 Collection<RegistrationStatus> includedStatus,
87 boolean isCount, Class<R> returnClass) {
88
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 ";
94
95 ReferenceType refTypeParameter = null;
96
97 if (reference == null){
98 //do nothing
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 ";
104 where += " AND ("
105 + " nomRef =:ref "
106 + " OR (nomRef.type =:refType AND nomRef.inReference =:ref) "
107 + " OR desigRef =:ref "
108 + " OR (desigRef.type =:refType AND desigRef.inReference =:ref)"
109 + ")";
110 refTypeParameter = ReferenceType.Section;
111 }else{ //ref is null
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))"
117 + ") "
118 ;
119 }
120 boolean hasStatus = includedStatus != null && !includedStatus.isEmpty();
121 if (hasStatus){
122 where += " AND r.status IN (:status) ";
123 }
124
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());
129 }
130 if(refTypeParameter != null){
131 query.setParameter("refType", refTypeParameter);
132 }
133 if (hasStatus){
134 query.setParameterList("status", includedStatus);
135 }
136 return query;
137 }
138
139 @Override
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);
148 }
149
150 @Override
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) {
154
155 Query<Registration> query = makeFilteredSearchQuery(submitterUuid, includedStatus, identifierFilterPattern,
156 taxonNameFilterPattern, referenceFilterPattern, typeDesignationStatusUuids, false, orderHints);
157
158 if(limit != null /*&& !doCount*/) {
159 query.setMaxResults(limit);
160 if(start != null) {
161 query.setFirstResult(start);
162 }
163 }
164
165 List<Registration> results = query.list();
166 defaultBeanInitializer.initializeAll(results, propertyPaths);
167
168 return results;
169 }
170
171 @Override
172 public List<Registration> list(UUID submitterUuid, Collection<RegistrationStatus> includedStatus, Collection<UUID> taxonNameUUIDs,
173 Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
174
175 Query query = makeByNameUUIDQuery(submitterUuid, includedStatus, taxonNameUUIDs, false, orderHints);
176
177 if(limit != null /*&& !doCount*/) {
178 query.setMaxResults(limit);
179 if(start != null) {
180 query.setFirstResult(start);
181 }
182 }
183
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);
189
190 return results;
191 }
192
193 @Override
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);
201 }
202
203 private Query makeByNameUUIDQuery(UUID submitterUuid, Collection<RegistrationStatus> includedStatus,
204 Collection<UUID> taxonNameUUIDs, boolean isCount, List<OrderHint> orderHints) {
205
206 Map<String, Object> parameters = new HashMap<>();
207
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 "
213 ;
214 String where = " WHERE (1=1) ";
215 String orderBy = "";
216 if(!isCount){
217 orderBy = orderByClause("r", orderHints).toString();
218 }
219
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);
224 }
225 if(includedStatus != null && includedStatus.size() > 0) {
226 where += " AND r.status in (:includedStatus)";
227 parameters.put("includedStatus", includedStatus);
228 }
229
230 where += " AND (r.name.uuid in(:nameUUIDs) OR typifiedNames.uuid in(:nameUUIDs))";
231 parameters.put("nameUUIDs", taxonNameUUIDs);
232
233
234 String hql = select + from + where + orderBy;
235 Query query = getSession().createQuery(hql);
236
237 for(String paramName : parameters.keySet()){
238 Object value = parameters.get(paramName);
239 if(value instanceof Collection){
240 query.setParameterList(paramName, (Collection)value);
241 } else {
242 query.setParameter(paramName, value);
243 }
244 }
245
246 return query;
247 }
248
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) {
252
253 Map<String, Object> parameters = new HashMap<>();
254
255 boolean doNameFilter = StringUtils.isNoneBlank(taxonNameFilterPattern);
256 boolean doReferenceFilter = StringUtils.isNoneBlank(referenceFilterPattern);
257 boolean doTypeStatusFilter = typeDesignationStatusUuids != null && typeDesignationStatusUuids.size() > 0;
258
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
265 + (doReferenceFilter
266 ? " LEFT JOIN desig.designationSource typeDesignationSource "
267 + " LEFT JOIN typeDesignationSource.citation typeDesignationCitation "
268 + " LEFT JOIN n.nomenclaturalSource nomSource "
269 + " LEFT JOIN nomSource.citation nomRef "
270 : "")
271 ;
272 // further JOIN
273 String where = " WHERE (1=1) ";
274 String orderBy = "";
275 if(!isCount){
276 orderBy = orderByClause("r", orderHints).toString();
277 }
278
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);
283 }
284 if(includedStatus != null && includedStatus.size() > 0) {
285 where += " AND r.status in (:includedStatus)";
286 parameters.put("includedStatus", includedStatus);
287 }
288 if(StringUtils.isNoneBlank(identifierFilterPattern)){
289 where += " AND r.identifier LIKE :identifierFilterPattern";
290 parameters.put("identifierFilterPattern", MatchMode.ANYWHERE.queryStringFrom(identifierFilterPattern));
291 }
292 if(doNameFilter){
293 where += " AND (r.name.titleCache LIKE :taxonNameFilterPattern OR typifiedNames.titleCache LIKE :taxonNameFilterPattern)";
294 parameters.put("taxonNameFilterPattern", MatchMode.ANYWHERE.queryStringFrom(taxonNameFilterPattern));
295 }
296 if(doReferenceFilter){
297 where += " AND (typeDesignationCitation.titleCache LIKE :referenceFilterPattern OR nomRef.titleCache LIKE :referenceFilterPattern)";
298 parameters.put("referenceFilterPattern", MatchMode.ANYWHERE.queryStringFrom(referenceFilterPattern));
299 }
300 if(doTypeStatusFilter){
301 boolean addNullFilter = false;
302 while(typeDesignationStatusUuids.contains(null)){
303 addNullFilter = true;
304 typeDesignationStatusUuids.remove(null);
305 }
306 String typeStatusWhere = "";
307 if(!typeDesignationStatusUuids.isEmpty()){
308 typeStatusWhere += " typeStatus.uuid in (:typeDesignationStatusUuids)";
309 parameters.put("typeDesignationStatusUuids", typeDesignationStatusUuids);
310 }
311 if(addNullFilter){
312 typeStatusWhere += (!typeStatusWhere.isEmpty() ? " OR ":"") + "typeStatus is null";
313 }
314 where += " AND ( " + typeStatusWhere + ")";
315 }
316 String hql = select + from + where + orderBy;
317 Query query = getSession().createQuery(hql);
318
319 for(String paramName : parameters.keySet()){
320 Object value = parameters.get(paramName);
321 if(value instanceof Collection){
322 query.setParameterList(paramName, (Collection)value);
323 } else {
324 query.setParameter(paramName, value);
325 }
326 }
327
328 return query;
329 }
330 }