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.config.SumarisConfiguration;
27 import net.sumaris.core.dao.administration.programStrategy.ProgramDao;
28 import net.sumaris.core.dao.administration.user.DepartmentDao;
29 import net.sumaris.core.dao.administration.user.PersonDao;
30 import net.sumaris.core.dao.referential.location.LocationDao;
31 import net.sumaris.core.dao.technical.SortDirection;
32 import net.sumaris.core.model.QualityFlagEnum;
33 import net.sumaris.core.model.administration.programStrategy.Program;
34 import net.sumaris.core.model.data.Trip;
35 import net.sumaris.core.model.referential.QualityFlag;
36 import net.sumaris.core.model.referential.location.Location;
37 import net.sumaris.core.util.Beans;
38 import net.sumaris.core.vo.administration.programStrategy.ProgramFetchOptions;
39 import net.sumaris.core.vo.administration.user.DepartmentVO;
40 import net.sumaris.core.vo.administration.user.PersonVO;
41 import net.sumaris.core.vo.data.DataFetchOptions;
42 import net.sumaris.core.vo.data.TripVO;
43 import net.sumaris.core.vo.data.VesselSnapshotVO;
44 import net.sumaris.core.vo.filter.TripFilterVO;
45 import org.apache.commons.collections4.CollectionUtils;
46 import org.apache.commons.lang3.StringUtils;
47 import org.hibernate.Session;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50 import org.springframework.beans.factory.annotation.Autowired;
51 import org.springframework.dao.DataRetrievalFailureException;
52 import org.springframework.stereotype.Repository;
53
54 import javax.persistence.EntityManager;
55 import javax.persistence.TypedQuery;
56 import javax.persistence.criteria.*;
57 import java.sql.Timestamp;
58 import java.util.Date;
59 import java.util.List;
60 import java.util.Objects;
61 import java.util.Set;
62 import java.util.stream.Collectors;
63
64 @Repository("tripDao")
65 public class TripDaoImpl extends BaseDataDaoImpl implements TripDao {
66
67
68
69
70 private static final Logger log =
71 LoggerFactory.getLogger(TripDaoImpl.class);
72
73 @Autowired
74 private SumarisConfiguration config;
75
76 @Autowired
77 private LocationDao locationDao;
78
79 @Autowired
80 private PersonDao personDao;
81
82 @Autowired
83 private DepartmentDao departmentDao;
84
85 @Autowired
86 private ProgramDao programDao;
87
88 public TripDaoImpl() {
89 super();
90 }
91
92 @Override
93 @SuppressWarnings("unchecked")
94 public List<TripVO> findAll(int offset, int size, String sortAttribute,
95 SortDirection sortDirection,
96 DataFetchOptions fieldOptions) {
97
98 CriteriaBuilder builder = entityManager.getCriteriaBuilder();
99 CriteriaQuery<Trip> query = builder.createQuery(Trip.class);
100 Root<Trip> tripRoot = query.from(Trip.class);
101 query.select(tripRoot)
102 .distinct(true);
103
104
105 if (StringUtils.isNotBlank(sortAttribute)) {
106 Expression<?> sortExpression = tripRoot.get(sortAttribute);
107 query.orderBy(SortDirection.DESC.equals(sortDirection) ?
108 builder.desc(sortExpression) :
109 builder.asc(sortExpression)
110 );
111 }
112
113
114 Session session = getSession();
115 if (fieldOptions.isWithRecorderDepartment() || fieldOptions.isWithRecorderPerson())
116 session.enableFetchProfile(Trip.FETCH_PROFILE_RECORDER);
117 if (fieldOptions.isWithObservers())
118 session.enableFetchProfile(Trip.FETCH_PROFILE_OBSERVERS);
119 session.enableFetchProfile(Trip.FETCH_PROFILE_LOCATION);
120
121 return toTripVOs(entityManager.createQuery(query)
122 .setFirstResult(offset)
123 .setMaxResults(size)
124 .getResultList(), fieldOptions);
125 }
126
127 @Override
128 @SuppressWarnings("unchecked")
129 public List<TripVO> findAll(TripFilterVO filter, int offset, int size, String sortAttribute,
130 SortDirection sortDirection,
131 DataFetchOptions fieldOptions) {
132 Preconditions.checkNotNull(filter);
133 Preconditions.checkArgument(offset >= 0);
134 Preconditions.checkArgument(size > 0);
135
136 Integer programId = null;
137 if (StringUtils.isNotBlank(filter.getProgramLabel())) {
138 programId = programDao.getByLabel(filter.getProgramLabel()).getId();
139 }
140
141
142
143
144 CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
145 CriteriaQuery<Trip> query = builder.createQuery(Trip.class);
146 Root<Trip> root = query.from(Trip.class);
147
148 ParameterExpression<Date> startDateParam = builder.parameter(Date.class);
149 ParameterExpression<Date> endDateParam = builder.parameter(Date.class);
150 ParameterExpression<Integer> locationIdParam = builder.parameter(Integer.class);
151 ParameterExpression<Integer> programIdParam = builder.parameter(Integer.class);
152 ParameterExpression<Integer> vesselIdParam = builder.parameter(Integer.class);
153
154 query.select(root)
155 .where(builder.and(
156
157 builder.or(
158 builder.isNull(programIdParam),
159 builder.equal(root.get(Trip.Fields.PROGRAM).get(Program.Fields.ID), programIdParam)
160 ),
161
162 builder.or(
163 builder.isNull(startDateParam),
164 builder.not(builder.lessThan(root.get(Trip.Fields.RETURN_DATE_TIME), startDateParam))
165 ),
166
167 builder.or(
168 builder.isNull(endDateParam),
169 builder.not(builder.greaterThan(root.get(Trip.Fields.DEPARTURE_DATE_TIME), endDateParam))
170 ),
171
172 builder.or(
173 builder.isNull(locationIdParam),
174 builder.equal(root.get(Trip.Fields.DEPARTURE_LOCATION).get(Location.Fields.ID), locationIdParam),
175 builder.equal(root.get(Trip.Fields.RETURN_LOCATION).get(Location.Fields.ID), locationIdParam)
176 ),
177
178 builder.or(
179 builder.isNull(vesselIdParam),
180 builder.equal(root.get(Trip.Fields.VESSEL).get(Location.Fields.ID), vesselIdParam)
181 )
182 ));
183
184
185 if (StringUtils.isNotBlank(sortAttribute)) {
186 Expression<?> sortExpression = root.get(sortAttribute);
187 query.orderBy(SortDirection.DESC.equals(sortDirection) ?
188 builder.desc(sortExpression) :
189 builder.asc(sortExpression)
190 );
191 }
192
193 TypedQuery<Trip> q = getEntityManager().createQuery(query)
194 .setParameter(programIdParam, programId)
195 .setParameter(startDateParam, filter.getStartDate())
196 .setParameter(endDateParam, filter.getEndDate())
197 .setParameter(locationIdParam, filter.getLocationId())
198 .setParameter(vesselIdParam, filter.getVesselId())
199 .setFirstResult(offset)
200 .setMaxResults(size);
201 return toTripVOs(q.getResultList(), fieldOptions);
202 }
203
204 @Override
205 public Long countByFilter(TripFilterVO filter) {
206
207 CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
208 CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);
209
210 Integer programId = null;
211 if (filter != null && StringUtils.isNotBlank(filter.getProgramLabel())) {
212 programId = programDao.getByLabel(filter.getProgramLabel()).getId();
213 }
214
215 ParameterExpression<Date> startDateParam = builder.parameter(Date.class);
216 ParameterExpression<Date> endDateParam = builder.parameter(Date.class);
217 ParameterExpression<Integer> locationIdParam = builder.parameter(Integer.class);
218 ParameterExpression<Integer> programIdParam = builder.parameter(Integer.class);
219
220 Root<Trip> root = criteriaQuery.from(Trip.class);
221 criteriaQuery.select(builder.count(root));
222 if (filter != null) {
223 criteriaQuery.where(builder.and(
224
225 builder.or(
226 builder.isNull(programIdParam),
227 builder.equal(root.get(Trip.Fields.PROGRAM).get(Program.Fields.ID), programIdParam)
228 ),
229
230 builder.or(
231 builder.isNull(startDateParam),
232 builder.not(builder.lessThan(root.get(Trip.Fields.RETURN_DATE_TIME), startDateParam))
233 ),
234
235 builder.or(
236 builder.isNull(endDateParam),
237 builder.not(builder.greaterThan(root.get(Trip.Fields.DEPARTURE_DATE_TIME), endDateParam))
238 ),
239
240 builder.or(
241 builder.isNull(locationIdParam),
242 builder.equal(root.get(Trip.Fields.DEPARTURE_LOCATION).get(Location.Fields.ID), locationIdParam),
243 builder.equal(root.get(Trip.Fields.RETURN_LOCATION).get(Location.Fields.ID), locationIdParam)
244 )
245 ));
246 }
247
248 if (filter != null) {
249 return getEntityManager()
250 .createQuery(criteriaQuery)
251 .setParameter(programIdParam, programId)
252 .setParameter(startDateParam, filter.getStartDate())
253 .setParameter(endDateParam, filter.getEndDate())
254 .setParameter(locationIdParam, filter.getLocationId())
255 .getSingleResult();
256 } else {
257 return getEntityManager()
258 .createQuery(criteriaQuery)
259 .getSingleResult();
260 }
261 }
262
263 @Override
264 public TripVO get(int id) {
265 Trip entity = get(Trip.class, id);
266 return toVO(entity);
267 }
268
269 @Override
270 public TripVOref="../../../../../net/sumaris/core/vo/data/TripVO.html#TripVO">TripVO save(TripVO source) {
271 Preconditions.checkNotNull(source);
272
273 EntityManager entityManager = getEntityManager();
274 Trip entity = null;
275 if (source.getId() != null && source.getId().intValue() >= 0) {
276 entity = get(Trip.class, source.getId());
277 }
278 boolean isNew = (entity == null);
279 if (isNew) {
280 entity = new Trip();
281 } else {
282
283 checkUpdateDateForUpdate(source, entity);
284
285
286 lockForUpdate(entity);
287 }
288
289
290 tripVOToEntity(source, entity, true);
291
292
293 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
294 entity.setUpdateDate(newUpdateDate);
295
296
297 if (isNew) {
298
299 entity.setId(null);
300
301
302 entity.setCreationDate(newUpdateDate);
303 source.setCreationDate(newUpdateDate);
304
305 entityManager.persist(entity);
306 source.setId(entity.getId());
307 } else {
308 entityManager.merge(entity);
309 }
310
311 source.setUpdateDate(newUpdateDate);
312
313
314
315
316
317 return source;
318 }
319
320 @Override
321 public void delete(int id) {
322
323 log.debug(String.format("Deleting trip {id=%s}...", id));
324 delete(Trip.class, id);
325 }
326
327 @Override
328 public TripVO toVO(Trip source) {
329 return toTripVO(source, null);
330 }
331
332 @Override
333 public TripVO="../../../../../net/sumaris/core/vo/data/TripVO.html#TripVO">TripVO control(TripVO source) {
334 Preconditions.checkNotNull(source);
335
336 Trip entity = get(Trip.class, source.getId());
337 if (entity == null) {
338 throw new DataRetrievalFailureException(String.format("Trip {%s} not found", source.getId()));
339 }
340
341
342 checkUpdateDateForUpdate(source, entity);
343
344
345 lockForUpdate(entity);
346
347
348 Date controlDate = getDatabaseCurrentTimestamp();
349 entity.setControlDate(controlDate);
350
351
352 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
353 entity.setUpdateDate(newUpdateDate);
354
355
356 getEntityManager().merge(entity);
357
358
359 source.setControlDate(controlDate);
360 source.setUpdateDate(newUpdateDate);
361
362 return source;
363 }
364
365 @Override
366 public TripVO"../../../../../net/sumaris/core/vo/data/TripVO.html#TripVO">TripVO validate(TripVO source) {
367 Preconditions.checkNotNull(source);
368
369 Trip entity = get(Trip.class, source.getId());
370 if (entity == null) {
371 throw new DataRetrievalFailureException(String.format("Trip {%s} not found", source.getId()));
372 }
373
374
375 checkUpdateDateForUpdate(source, entity);
376
377
378
379
380
381 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
382 entity.setUpdateDate(newUpdateDate);
383
384
385 entity.setValidationDate(newUpdateDate);
386
387
388 getEntityManager().merge(entity);
389
390
391 source.setValidationDate(newUpdateDate);
392 source.setUpdateDate(newUpdateDate);
393
394 return source;
395 }
396
397 @Override
398 public TripVO./../../../../net/sumaris/core/vo/data/TripVO.html#TripVO">TripVO unvalidate(TripVO source) {
399 Preconditions.checkNotNull(source);
400
401 Trip entity = get(Trip.class, source.getId());
402 if (entity == null) {
403 throw new DataRetrievalFailureException(String.format("Trip {%s} not found", source.getId()));
404 }
405
406
407 checkUpdateDateForUpdate(source, entity);
408
409
410
411
412
413 entity.setValidationDate(null);
414 entity.setQualificationDate(null);
415 entity.setQualityFlag(load(QualityFlag.class, QualityFlagEnum.NOT_QUALIFED.getId()));
416
417
418 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
419 entity.setUpdateDate(newUpdateDate);
420
421
422 getEntityManager().merge(entity);
423
424
425 source.setValidationDate(null);
426 source.setQualificationDate(null);
427 source.setQualityFlagId(QualityFlagEnum.NOT_QUALIFED.getId());
428 source.setUpdateDate(newUpdateDate);
429
430 return source;
431 }
432
433 @Override
434 public TripVO="../../../../../net/sumaris/core/vo/data/TripVO.html#TripVO">TripVO qualify(TripVO source) {
435 Preconditions.checkNotNull(source);
436
437 Trip entity = get(Trip.class, source.getId());
438 if (entity == null) {
439 throw new DataRetrievalFailureException(String.format("Trip {%s} not found", source.getId()));
440 }
441
442
443 checkUpdateDateForUpdate(source, entity);
444
445
446
447
448
449
450 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
451 entity.setUpdateDate(newUpdateDate);
452
453 int qualityFlagId = source.getQualityFlagId() != null ? source.getQualityFlagId().intValue() : 0;
454
455
456 if (qualityFlagId == QualityFlagEnum.NOT_QUALIFED.getId()) {
457 entity.setQualificationDate(null);
458 }
459 else {
460 entity.setQualificationDate(newUpdateDate);
461 }
462
463 entity.setQualityFlag(get(QualityFlag.class, Integer.valueOf(qualityFlagId)));
464
465
466
467
468
469 getEntityManager().merge(entity);
470
471
472 source.setQualificationDate(entity.getQualificationDate());
473 source.setQualityFlagId(entity.getQualityFlag() != null ? entity.getQualityFlag().getId() : 0);
474 source.setUpdateDate(newUpdateDate);
475
476 return source;
477 }
478
479
480
481 protected List<TripVO> toTripVOs(List<Trip> source, DataFetchOptions fieldOptions) {
482 return source.stream()
483 .map(item -> this.toTripVO(item, fieldOptions))
484 .filter(Objects::nonNull)
485 .collect(Collectors.toList());
486 }
487
488 protected TripVO toTripVO(Trip source, DataFetchOptions fieldOptions) {
489 if (source == null) return null;
490
491 TripVOTripVO.html#TripVO">TripVO target = new TripVO();
492
493 Beans.copyProperties(source, target);
494
495
496 target.setProgram(programDao.toProgramVO(source.getProgram(),
497 ProgramFetchOptions.builder().withProperties(false).build()));
498
499
500 VesselSnapshotVOtml#VesselSnapshotVO">VesselSnapshotVO vesselSnapshot = new VesselSnapshotVO();
501 vesselSnapshot.setId(source.getVessel().getId());
502 target.setVesselSnapshot(vesselSnapshot);
503 target.setQualityFlagId(source.getQualityFlag().getId());
504
505
506 target.setDepartureLocation(locationDao.toLocationVO(source.getDepartureLocation()));
507 target.setReturnLocation(locationDao.toLocationVO(source.getReturnLocation()));
508
509
510 if ((fieldOptions == null || fieldOptions.isWithRecorderDepartment()) && source.getRecorderDepartment() != null) {
511 DepartmentVO recorderDepartment = departmentDao.toDepartmentVO(source.getRecorderDepartment());
512 target.setRecorderDepartment(recorderDepartment);
513 }
514
515
516 if ((fieldOptions == null || fieldOptions.isWithRecorderPerson()) && source.getRecorderPerson() != null) {
517 PersonVO recorderPerson = personDao.toPersonVO(source.getRecorderPerson());
518 target.setRecorderPerson(recorderPerson);
519 }
520
521
522 if ((fieldOptions == null || fieldOptions.isWithObservers()) && CollectionUtils.isNotEmpty(source.getObservers())) {
523 Set<PersonVO> observers = source.getObservers().stream().map(personDao::toPersonVO).collect(Collectors.toSet());
524 target.setObservers(observers);
525 }
526
527 return target;
528 }
529
530 protected void tripVOToEntity(TripVO source, Trip target, boolean copyIfNull) {
531
532 copyRootDataProperties(source, target, copyIfNull);
533
534
535 copyObservers(source, target, copyIfNull);
536
537
538 copyVessel(source, target, copyIfNull);
539
540
541 if (copyIfNull || source.getDepartureLocation() != null) {
542 if (source.getDepartureLocation() == null || source.getDepartureLocation().getId() == null) {
543 target.setDepartureLocation(null);
544 } else {
545 target.setDepartureLocation(load(Location.class, source.getDepartureLocation().getId()));
546 }
547 }
548
549
550 if (copyIfNull || source.getReturnLocation() != null) {
551 if (source.getReturnLocation() == null || source.getReturnLocation().getId() == null) {
552 target.setReturnLocation(null);
553 } else {
554 target.setReturnLocation(load(Location.class, source.getReturnLocation().getId()));
555 }
556 }
557
558 }
559 }