1 package net.sumaris.core.dao.data;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import com.google.common.base.Preconditions;
26 import net.sumaris.core.dao.administration.programStrategy.ProgramDao;
27 import net.sumaris.core.dao.administration.user.DepartmentDao;
28 import net.sumaris.core.dao.administration.user.PersonDao;
29 import net.sumaris.core.dao.referential.location.LocationDao;
30 import net.sumaris.core.dao.technical.SortDirection;
31 import net.sumaris.core.dao.technical.model.IEntity;
32 import net.sumaris.core.model.administration.programStrategy.Program;
33 import net.sumaris.core.model.administration.user.Person;
34 import net.sumaris.core.model.data.ObservedLocation;
35 import net.sumaris.core.model.referential.location.Location;
36 import net.sumaris.core.util.Beans;
37 import net.sumaris.core.vo.administration.programStrategy.ProgramFetchOptions;
38 import net.sumaris.core.vo.administration.user.DepartmentVO;
39 import net.sumaris.core.vo.administration.user.PersonVO;
40 import net.sumaris.core.vo.data.DataFetchOptions;
41 import net.sumaris.core.vo.data.ObservedLocationVO;
42 import net.sumaris.core.vo.filter.ObservedLocationFilterVO;
43 import org.apache.commons.collections4.CollectionUtils;
44 import org.apache.commons.lang3.StringUtils;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.beans.factory.annotation.Autowired;
48 import org.springframework.stereotype.Repository;
49
50 import javax.persistence.EntityManager;
51 import javax.persistence.TypedQuery;
52 import javax.persistence.criteria.*;
53 import java.sql.Timestamp;
54 import java.util.*;
55 import java.util.stream.Collectors;
56
57 @Repository("observedLocationDao")
58 public class ObservedLocationDaoImpl extends BaseDataDaoImpl implements ObservedLocationDao {
59
60
61
62
63 private static final Logger log =
64 LoggerFactory.getLogger(ObservedLocationDaoImpl.class);
65
66 @Autowired
67 private LocationDao locationDao;
68
69 @Autowired
70 private PersonDao personDao;
71
72 @Autowired
73 private DepartmentDao departmentDao;
74
75 @Autowired
76 private ProgramDao programDao;
77
78 public ObservedLocationDaoImpl() {
79 super();
80 }
81
82 @Override
83 @SuppressWarnings("unchecked")
84 public List<ObservedLocationVO> getAll(int offset, int size, String sortAttribute, SortDirection sortDirection, DataFetchOptions fetchOptions) {
85
86 CriteriaBuilder builder = entityManager.getCriteriaBuilder();
87 CriteriaQuery<ObservedLocation> query = builder.createQuery(ObservedLocation.class);
88 Root<ObservedLocation> observedLocationRoot = query.from(ObservedLocation.class);
89 query.select(observedLocationRoot)
90 .distinct(true);
91
92
93 if (StringUtils.isNotBlank(sortAttribute)) {
94 Expression<?> sortExpression = observedLocationRoot.get(sortAttribute);
95 query.orderBy(SortDirection.DESC.equals(sortDirection) ?
96 builder.desc(sortExpression) :
97 builder.asc(sortExpression)
98 );
99 }
100
101 return toVOs(entityManager.createQuery(query).
102 setFirstResult(offset)
103 .setMaxResults(size)
104 .getResultList(), fetchOptions);
105 }
106
107 @Override
108 @SuppressWarnings("unchecked")
109 public List<ObservedLocationVO> findByFilter(ObservedLocationFilterVO filter, int offset, int size, String sortAttribute,
110 SortDirection sortDirection, DataFetchOptions fetchOptions) {
111 Preconditions.checkNotNull(filter);
112 Preconditions.checkArgument(offset >= 0);
113 Preconditions.checkArgument(size > 0);
114
115 Integer programId = null;
116 if (StringUtils.isNotBlank(filter.getProgramLabel())) {
117 programId = programDao.getByLabel(filter.getProgramLabel()).getId();
118 }
119
120
121
122
123 CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
124 CriteriaQuery<ObservedLocation> query = builder.createQuery(ObservedLocation.class);
125 Root<ObservedLocation> root = query.from(ObservedLocation.class);
126
127 ParameterExpression<Date> startDateParam = builder.parameter(Date.class);
128 ParameterExpression<Date> endDateParam = builder.parameter(Date.class);
129 ParameterExpression<Integer> locationIdParam = builder.parameter(Integer.class);
130 ParameterExpression<Integer> programIdParam = builder.parameter(Integer.class);
131
132 query.select(root)
133 .where(builder.and(
134
135 builder.or(
136 builder.isNull(programIdParam),
137 builder.equal(root.get(ObservedLocation.Fields.PROGRAM).get(Program.Fields.ID), programIdParam)
138 ),
139
140 builder.or(
141 builder.isNull(startDateParam),
142 builder.not(builder.lessThan(root.get(ObservedLocation.Fields.END_DATE_TIME), startDateParam))
143 ),
144
145 builder.or(
146 builder.isNull(endDateParam),
147 builder.not(builder.greaterThan(root.get(ObservedLocation.Fields.START_DATE_TIME), endDateParam))
148 ),
149
150 builder.or(
151 builder.isNull(locationIdParam),
152 builder.equal(root.get(ObservedLocation.Fields.LOCATION).get(Location.Fields.ID), locationIdParam)
153 )
154 ));
155
156
157 if (StringUtils.isNotBlank(sortAttribute)) {
158 Expression<?> sortExpression = root.get(sortAttribute);
159 query.orderBy(SortDirection.DESC.equals(sortDirection) ?
160 builder.desc(sortExpression) :
161 builder.asc(sortExpression)
162 );
163 }
164
165 TypedQuery<ObservedLocation> q = getEntityManager().createQuery(query)
166 .setParameter(programIdParam, programId)
167 .setParameter(startDateParam, filter.getStartDate())
168 .setParameter(endDateParam, filter.getEndDate())
169 .setParameter(locationIdParam, filter.getLocationId())
170 .setFirstResult(offset)
171 .setMaxResults(size);
172 return toVOs(q.getResultList(), fetchOptions);
173 }
174
175 @Override
176 public Long countByFilter(ObservedLocationFilterVO filter) {
177
178 CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
179 CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);
180
181 Integer programId = null;
182 if (filter != null && StringUtils.isNotBlank(filter.getProgramLabel())) {
183 programId = programDao.getByLabel(filter.getProgramLabel()).getId();
184 }
185
186 ParameterExpression<Date> startDateParam = builder.parameter(Date.class);
187 ParameterExpression<Date> endDateParam = builder.parameter(Date.class);
188 ParameterExpression<Integer> locationIdParam = builder.parameter(Integer.class);
189 ParameterExpression<Integer> programIdParam = builder.parameter(Integer.class);
190
191 Root<ObservedLocation> root = criteriaQuery.from(ObservedLocation.class);
192 criteriaQuery.select(builder.count(root));
193 if (filter != null) {
194 criteriaQuery.where(builder.and(
195
196 builder.or(
197 builder.isNull(programIdParam),
198 builder.equal(root.get(ObservedLocation.Fields.PROGRAM).get(Program.Fields.ID), programIdParam)
199 ),
200
201 builder.or(
202 builder.isNull(startDateParam),
203 builder.not(builder.lessThan(root.get(ObservedLocation.Fields.END_DATE_TIME), startDateParam))
204 ),
205
206 builder.or(
207 builder.isNull(endDateParam),
208 builder.not(builder.greaterThan(root.get(ObservedLocation.Fields.START_DATE_TIME), endDateParam))
209 ),
210
211 builder.or(
212 builder.isNull(locationIdParam),
213 builder.equal(root.get(ObservedLocation.Fields.LOCATION).get(Location.Fields.ID), locationIdParam)
214 )
215 ));
216 }
217
218 if (filter != null) {
219 return getEntityManager()
220 .createQuery(criteriaQuery)
221 .setParameter(programIdParam, programId)
222 .setParameter(startDateParam, filter.getStartDate())
223 .setParameter(endDateParam, filter.getEndDate())
224 .setParameter(locationIdParam, filter.getLocationId())
225 .getSingleResult();
226 } else {
227 return getEntityManager()
228 .createQuery(criteriaQuery)
229 .getSingleResult();
230 }
231 }
232
233 @Override
234 public ObservedLocationVO get(int id) {
235 ObservedLocation entity = get(ObservedLocation.class, id);
236 return toVO(entity, null);
237 }
238
239 @Override
240 public <T> T get(int id, Class<T> targetClass) {
241 if (targetClass.isAssignableFrom(ObservedLocation.class)) return (T) get(ObservedLocation.class, id);
242 if (targetClass.isAssignableFrom(ObservedLocationVO.class)) return (T) get(id);
243 throw new IllegalArgumentException("Unable to convert into " + targetClass.getName());
244 }
245
246 @Override
247 public ObservedLocationVO./../../net/sumaris/core/vo/data/ObservedLocationVO.html#ObservedLocationVO">ObservedLocationVO save(ObservedLocationVO source) {
248 Preconditions.checkNotNull(source);
249
250 EntityManager entityManager = getEntityManager();
251 ObservedLocation entity = null;
252 if (source.getId() != null) {
253 entity = get(ObservedLocation.class, source.getId());
254 }
255 boolean isNew = (entity == null);
256 if (isNew) {
257 entity = new ObservedLocation();
258 } else {
259
260 checkUpdateDateForUpdate(source, entity);
261
262
263 lockForUpdate(entity);
264 }
265
266
267 observedLocationVOToEntity(source, entity, true);
268
269
270 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
271 entity.setUpdateDate(newUpdateDate);
272
273
274 if (isNew) {
275
276 entity.setCreationDate(newUpdateDate);
277 source.setCreationDate(newUpdateDate);
278
279 entityManager.persist(entity);
280 source.setId(entity.getId());
281 } else {
282 entityManager.merge(entity);
283 }
284
285 source.setUpdateDate(newUpdateDate);
286
287
288
289
290
291 return source;
292 }
293
294 @Override
295 public void delete(int id) {
296
297 log.debug(String.format("Deleting observedLocation {id=%s}...", id));
298 delete(ObservedLocation.class, id);
299 }
300
301 @Override
302 public ObservedLocationVO toVO(ObservedLocation source) {
303 return toVO(source, null);
304 }
305
306 @Override
307 public ObservedLocationVO./../net/sumaris/core/vo/data/ObservedLocationVO.html#ObservedLocationVO">ObservedLocationVO control(ObservedLocationVO source) {
308 Preconditions.checkNotNull(source);
309
310 ObservedLocation entity = get(ObservedLocation.class, source.getId());
311
312
313 checkUpdateDateForUpdate(source, entity);
314
315
316 lockForUpdate(entity);
317
318
319 Date controlDate = getDatabaseCurrentTimestamp();
320 entity.setControlDate(controlDate);
321
322
323 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
324 entity.setUpdateDate(newUpdateDate);
325
326
327 getEntityManager().merge(entity);
328
329
330 source.setControlDate(controlDate);
331 source.setUpdateDate(newUpdateDate);
332
333 return source;
334 }
335
336 @Override
337 public ObservedLocationVO/../net/sumaris/core/vo/data/ObservedLocationVO.html#ObservedLocationVO">ObservedLocationVO validate(ObservedLocationVO source) {
338 Preconditions.checkNotNull(source);
339
340 ObservedLocation entity = get(ObservedLocation.class, source.getId());
341
342
343 checkUpdateDateForUpdate(source, entity);
344
345
346
347
348
349 Date validationDate = getDatabaseCurrentTimestamp();
350 entity.setValidationDate(validationDate);
351
352
353 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
354 entity.setUpdateDate(newUpdateDate);
355
356
357
358
359
360 source.setValidationDate(validationDate);
361 source.setUpdateDate(newUpdateDate);
362
363 return source;
364 }
365
366 @Override
367 public ObservedLocationVO./net/sumaris/core/vo/data/ObservedLocationVO.html#ObservedLocationVO">ObservedLocationVO unvalidate(ObservedLocationVO source) {
368 Preconditions.checkNotNull(source);
369
370 ObservedLocation entity = get(ObservedLocation.class, source.getId());
371
372
373 checkUpdateDateForUpdate(source, entity);
374
375
376
377
378
379 entity.setValidationDate(null);
380
381
382 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
383 entity.setUpdateDate(newUpdateDate);
384
385
386
387
388
389 source.setValidationDate(null);
390 source.setUpdateDate(newUpdateDate);
391
392 return source;
393 }
394
395
396
397 protected List<ObservedLocationVO> toVOs(List<ObservedLocation> source, DataFetchOptions fetchOptions) {
398 return source.stream()
399 .map(item -> toVO(item, fetchOptions))
400 .filter(Objects::nonNull)
401 .collect(Collectors.toList());
402 }
403
404
405 protected ObservedLocationVO toVO(ObservedLocation source, DataFetchOptions fetchOptions) {
406 if (source == null) return null;
407
408 ObservedLocationVOtionVO.html#ObservedLocationVO">ObservedLocationVO target = new ObservedLocationVO();
409
410 Beans.copyProperties(source, target);
411
412
413 if (target.getEndDateTime() != null && target.getEndDateTime().equals(target.getStartDateTime())) {
414 target.setEndDateTime(null);
415 }
416
417
418 target.setProgram(programDao.toProgramVO(source.getProgram(),
419 ProgramFetchOptions.builder().withProperties(false)
420 .build()));
421
422
423 target.setQualityFlagId(source.getQualityFlag().getId());
424
425
426 target.setLocation(locationDao.toLocationVO(source.getLocation()));
427
428
429 if (fetchOptions == null || fetchOptions.isWithRecorderDepartment()) {
430 DepartmentVO recorderDepartment = departmentDao.toDepartmentVO(source.getRecorderDepartment());
431 target.setRecorderDepartment(recorderDepartment);
432 }
433
434
435 if ((fetchOptions == null || fetchOptions.isWithRecorderPerson()) && source.getRecorderPerson() != null) {
436 PersonVO recorderPerson = personDao.toPersonVO(source.getRecorderPerson());
437 target.setRecorderPerson(recorderPerson);
438 }
439
440
441 if ((fetchOptions == null || fetchOptions.isWithObservers()) && CollectionUtils.isNotEmpty(source.getObservers())) {
442 Set<PersonVO> observers = source.getObservers().stream().map(personDao::toPersonVO).collect(Collectors.toSet());
443 target.setObservers(observers);
444 }
445
446 return target;
447 }
448
449 protected void observedLocationVOToEntity(ObservedLocationVO source, ObservedLocation target, boolean copyIfNull) {
450
451
452 copyRootDataProperties(source, target, copyIfNull);
453
454
455 if (target.getEndDateTime() == null) {
456 target.setEndDateTime(target.getStartDateTime());
457 }
458
459
460 if (copyIfNull || source.getLocation() != null) {
461 if (source.getLocation() == null || source.getLocation().getId() == null) {
462 target.setLocation(null);
463 } else {
464 target.setLocation(load(Location.class, source.getLocation().getId()));
465 }
466 }
467
468
469 if (copyIfNull || source.getObservers() != null) {
470 if (CollectionUtils.isEmpty(source.getObservers())) {
471 if (CollectionUtils.isNotEmpty(target.getObservers())) {
472 target.getObservers().clear();
473 }
474 } else {
475 Map<Integer, Person> observersToRemove = Beans.splitById(target.getObservers());
476 source.getObservers().stream()
477 .map(IEntity::getId)
478 .forEach(personId -> {
479 if (observersToRemove.remove(personId) == null) {
480
481 target.getObservers().add(load(Person.class, personId));
482 }
483 });
484
485
486 target.getObservers().removeAll(observersToRemove.values());
487 }
488 }
489 }
490 }