1 package net.sumaris.core.dao.technical.extraction;
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 com.google.common.collect.ImmutableList;
27 import com.google.common.collect.Lists;
28 import net.sumaris.core.dao.administration.user.DepartmentDao;
29 import net.sumaris.core.dao.administration.user.PersonDao;
30 import net.sumaris.core.dao.data.DataDaos;
31 import net.sumaris.core.dao.technical.hibernate.HibernateDaoSupport;
32 import net.sumaris.core.model.referential.Status;
33 import net.sumaris.core.model.referential.StatusEnum;
34 import net.sumaris.core.model.technical.extraction.*;
35 import net.sumaris.core.util.Beans;
36 import net.sumaris.core.util.StringUtils;
37 import net.sumaris.core.vo.technical.extraction.*;
38 import org.apache.commons.collections4.CollectionUtils;
39 import org.apache.commons.collections4.MapUtils;
40 import org.apache.commons.lang3.ArrayUtils;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43 import org.springframework.beans.factory.annotation.Autowired;
44 import org.springframework.stereotype.Repository;
45
46 import javax.persistence.EntityManager;
47 import javax.persistence.TypedQuery;
48 import javax.persistence.criteria.CriteriaBuilder;
49 import javax.persistence.criteria.CriteriaQuery;
50 import javax.persistence.criteria.ParameterExpression;
51 import javax.persistence.criteria.Root;
52 import java.sql.Timestamp;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Objects;
56 import java.util.Optional;
57 import java.util.stream.Collectors;
58
59
60
61
62 @Repository("extractionProductDao")
63 public class ExtractionProductDaoImpl extends HibernateDaoSupport implements ExtractionProductDao {
64
65
66
67
68 private static final Logger log =
69 LoggerFactory.getLogger(ExtractionProductDaoImpl.class);
70
71 @Autowired
72 private DepartmentDao departmentDao;
73
74 @Autowired
75 private PersonDao personDao;
76
77 @Override
78 public List<ExtractionProductVO> findByFilter(ExtractionProductFilterVO filter, ProductFetchOptions fetchOptions) {
79 Preconditions.checkNotNull(filter);
80 Preconditions.checkArgument(ArrayUtils.isNotEmpty(filter.getStatusIds()));
81
82 StringBuilder hqlQuery = new StringBuilder();
83 hqlQuery.append("from ExtractionProduct p where p.status.id IN (:statusIds)");
84
85 if (filter.getDepartmentId() != null) {
86 hqlQuery.append(" and p.recorderDepartment.id = :departmentId");
87 }
88
89 TypedQuery<ExtractionProduct> query = getEntityManager().createQuery(hqlQuery.toString(), ExtractionProduct.class)
90 .setParameter("statusIds", ImmutableList.copyOf(filter.getStatusIds()));
91
92 if (filter.getDepartmentId() != null) {
93 query.setParameter("departmentId", filter.getDepartmentId());
94 }
95
96 return query
97 .getResultStream()
98 .map(p -> toProductVO(p, fetchOptions))
99 .collect(Collectors.toList());
100 }
101
102 @Override
103 public ExtractionProductVO getByLabel(String label, ProductFetchOptions fetchOptions) {
104 Preconditions.checkNotNull(label);
105
106 return toProductVO(getEntityManager().createQuery("from ExtractionProduct p where upper(p.label) =:label", ExtractionProduct.class)
107 .setParameter("label", label.toUpperCase())
108 .getSingleResult(),
109 fetchOptions);
110 }
111
112 @Override
113 public Optional<ExtractionProductVO> get(int id, ProductFetchOptions fetchOptions) {
114 try {
115 return Optional.ofNullable(toProductVO(get(ExtractionProduct.class, id), fetchOptions));
116 } catch (Exception e) {
117 return Optional.empty();
118 }
119 }
120
121 @Override
122 public List<ExtractionProductColumnVO> getColumnsByIdAndTableLabel(int id, String tableLabel) {
123
124 CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
125 CriteriaQuery<ExtractionProductColumn> query = cb.createQuery(ExtractionProductColumn.class);
126 Root<ExtractionProductColumn> root = query.from(ExtractionProductColumn.class);
127
128 query.select(root);
129
130 ParameterExpression<Integer> productIdParam = cb.parameter(Integer.class);
131 ParameterExpression<String> tableLabelParam = cb.parameter(String.class);
132
133 query.where(
134 cb.and(
135 cb.equal(root.get(ExtractionProductColumn.Fields.TABLE)
136 .get(ExtractionProductTable.Fields.PRODUCT)
137 .get(ExtractionProduct.Fields.ID), productIdParam),
138 cb.equal(root.get(ExtractionProductColumn.Fields.TABLE)
139 .get(ExtractionProductTable.Fields.LABEL), tableLabelParam)
140 )
141 );
142
143
144 query.orderBy(cb.asc(root.get(ExtractionProductColumn.Fields.RANK_ORDER)));
145
146 return getEntityManager().createQuery(query)
147 .setParameter(productIdParam, id)
148 .setParameter(tableLabelParam, tableLabel)
149 .getResultStream()
150 .map(c -> toColumnVO(c, null ))
151 .collect(Collectors.toList());
152 }
153
154 @Override
155 public ExtractionProductVO/../../../net/sumaris/core/vo/technical/extraction/ExtractionProductVO.html#ExtractionProductVO">ExtractionProductVO save(ExtractionProductVO source) {
156 EntityManager entityManager = getEntityManager();
157 ExtractionProduct entity = null;
158 if (source.getId() != null) {
159 entity = get(ExtractionProduct.class, source.getId());
160 }
161 boolean isNew = (entity == null);
162 if (isNew) {
163 entity = new ExtractionProduct();
164 } else {
165
166 checkUpdateDateForUpdate(source, entity);
167
168
169 lockForUpdate(entity);
170 }
171
172
173 productVOToEntity(source, entity, true);
174
175
176 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
177 entity.setUpdateDate(newUpdateDate);
178
179
180 if (isNew) {
181
182 entity.setCreationDate(newUpdateDate);
183 source.setCreationDate(newUpdateDate);
184
185 entityManager.persist(entity);
186 source.setId(entity.getId());
187 }
188
189 source.setUpdateDate(newUpdateDate);
190 source.setLabel(entity.getLabel());
191
192 getSession().flush();
193 getSession().clear();
194
195
196 saveProductTables(source.getTables(), source.getId(), newUpdateDate);
197
198 getSession().flush();
199 getSession().clear();
200
201
202 saveProductStratum(source.getStratum(), source.getId(), newUpdateDate);
203
204
205 entityManager.merge(entity);
206
207 getSession().flush();
208 getSession().clear();
209
210 return source;
211 }
212
213 @Override
214 public void delete(int id) {
215 log.debug(String.format("Deleting product {id=%s}...", id));
216 delete(ExtractionProduct.class, id);
217 }
218
219
220
221 protected void productVOToEntity(ExtractionProductVO source, ExtractionProduct target, boolean copyIfNull) {
222
223 Beans.copyProperties(source, target);
224
225
226 if (source.getLabel() != null) {
227 String label = source.getLabel().toUpperCase();
228 target.setLabel(label);
229 }
230
231
232 if (copyIfNull || source.getStatusId() != null) {
233 if (source.getStatusId() == null) {
234 target.setStatus(null);
235 } else {
236 target.setStatus(load(Status.class, source.getStatusId()));
237 }
238 }
239
240
241 if (copyIfNull || source.getParentId() != null) {
242 if (source.getParentId() == null) {
243 target.setParent(null);
244 } else {
245 target.setParent(load(ExtractionProduct.class, source.getParentId()));
246 }
247 }
248
249
250 DataDaos.copyRecorderPerson(getEntityManager(), source, target, copyIfNull);
251
252
253 DataDaos.copyRecorderDepartment(getEntityManager(), source, target, copyIfNull);
254 if (target.getRecorderDepartment() == null && target.getRecorderPerson() != null) {
255
256 target.setRecorderDepartment(target.getRecorderPerson().getDepartment());
257 }
258 }
259
260 protected void saveProductTables(List<ExtractionProductTableVO> sources, int productId, Timestamp updateDate) {
261 ExtractionProduct parent = get(ExtractionProduct.class, productId);
262
263 final EntityManager em = getEntityManager();
264 if (CollectionUtils.isEmpty(sources)) {
265 if (parent.getTables() != null) {
266 List<ExtractionProductTable> toRemove = ImmutableList.copyOf(parent.getTables());
267 parent.getTables().clear();
268 toRemove.forEach(em::remove);
269 }
270 } else {
271 Map<String, ExtractionProductTable> existingItems = Beans.splitByProperty(
272 Beans.getList(parent.getTables()),
273 ExtractionProductTable.Fields.LABEL);
274 final Status enableStatus = load(Status.class, StatusEnum.ENABLE.getId());
275 if (parent.getTables() == null) {
276 parent.setTables(Lists.newArrayList());
277 }
278
279
280 sources.stream()
281 .filter(Objects::nonNull)
282 .forEach(source -> {
283 ExtractionProductTable target = existingItems.remove(source.getLabel());
284 boolean isNew = (target == null);
285 if (isNew) {
286 target = new ExtractionProductTable();
287 }
288 Beans.copyProperties(source, target);
289 target.setProduct(parent);
290 target.setStatus(enableStatus);
291 target.setUpdateDate(updateDate);
292 if (isNew) {
293 target.setCreationDate(updateDate);
294 em.persist(target);
295 source.setId(target.getId());
296 } else {
297 em.merge(target);
298 }
299
300 source.setUpdateDate(updateDate);
301
302 if (isNew) parent.getTables().add(target);
303 });
304
305 getSession().flush();
306
307
308
309 boolean hasColumns = sources.stream().anyMatch(source -> source != null && source.getColumns() != null);
310 if (hasColumns) {
311 sources.stream()
312 .filter(Objects::nonNull)
313 .forEach(source -> saveProductTableColumns(source.getColumns(), source.getId(), updateDate));
314 getSession().flush();
315 }
316
317
318 if (MapUtils.isNotEmpty(existingItems)) {
319 parent.getTables().removeAll(existingItems.values());
320 existingItems.values().forEach(em::remove);
321 }
322
323 }
324 }
325
326 protected void saveProductStratum(List<ExtractionProductStrataVO> sources, int productId, Timestamp updateDate) {
327 ExtractionProduct parent = get(ExtractionProduct.class, productId);
328
329 final EntityManager em = getEntityManager();
330 if (CollectionUtils.isEmpty(sources)) {
331 if (parent.getStratum() != null) {
332 List<ExtractionProductStrata> toRemove = ImmutableList.copyOf(parent.getStratum());
333 parent.getStratum().clear();
334 toRemove.forEach(em::remove);
335 }
336 } else {
337 Map<String, ExtractionProductStrata> existingItems = Beans.splitByProperty(parent.getStratum(), ExtractionProductStrata.Fields.LABEL);
338 Map<String, ExtractionProductTable> existingTables = Beans.splitByProperty(parent.getTables(), ExtractionProductTable.Fields.LABEL);
339 final Status enableStatus = load(Status.class, StatusEnum.ENABLE.getId());
340 if (parent.getStratum() == null) {
341 parent.setStratum(Lists.newArrayList());
342 }
343
344
345 sources.stream()
346 .filter(Objects::nonNull)
347 .forEach(source -> {
348 ExtractionProductStrata target = existingItems.remove(source.getLabel());
349 boolean isNew = (target == null);
350 if (isNew) {
351 target = new ExtractionProductStrata();
352 Beans.copyProperties(source, target);
353 }
354 else {
355 target.setName(source.getName());
356 target.setIsDefault(source.getIsDefault());
357 }
358 target.setProduct(parent);
359 target.setStatus(source.getStatusId() != null ? load(Status.class, source.getStatusId()) : enableStatus);
360 target.setUpdateDate(updateDate);
361
362
363 ExtractionProductTable table = StringUtils.isNotBlank(source.getSheetName())
364 ? existingTables.get(source.getSheetName())
365 : (existingTables.size() == 1 ? existingTables.values().iterator().next() : null);
366 if (table != null) {
367 target.setTable(table);
368 target.setTimeColumn(findColumnByName(table, source.getTimeColumnName()));
369 target.setSpaceColumn(findColumnByName(table, source.getSpaceColumnName()));
370 target.setAggColumn(findColumnByName(table, source.getAggColumnName()));
371 target.setTechColumn(findColumnByName(table, source.getTechColumnName()));
372 }
373 else {
374 target.setTable(null);
375 target.setTimeColumn(null);
376 target.setSpaceColumn(null);
377 target.setAggColumn(null);
378 target.setTechColumn(null);
379 }
380
381 if (isNew) {
382 target.setCreationDate(updateDate);
383 em.persist(target);
384 source.setId(target.getId());
385 } else {
386 em.merge(target);
387 }
388
389 source.setUpdateDate(updateDate);
390 });
391
392 getSession().flush();
393
394
395 if (MapUtils.isNotEmpty(existingItems)) {
396 parent.getStratum().removeAll(existingItems.values());
397 existingItems.values().forEach(em::remove);
398 }
399
400 }
401 }
402
403 protected void saveProductTableColumns(List<ExtractionProductColumnVO> sources, int tableId, Timestamp updateDate) {
404 final EntityManager em = getEntityManager();
405
406
407 ExtractionProductTable parent = get(ExtractionProductTable.class, tableId);
408
409 if (CollectionUtils.isEmpty(sources)) {
410 if (parent.getColumns() != null) {
411 List<ExtractionProductColumn> toRemove = ImmutableList.copyOf(parent.getColumns());
412 parent.getColumns().clear();
413 toRemove.forEach(em::remove);
414 }
415 } else {
416 Map<String, ExtractionProductColumn> existingItems = Beans.splitByProperty(
417 Beans.getList(parent.getColumns()),
418 ExtractionProductColumn.Fields.COLUMN_NAME);
419 if (parent.getColumns() == null) {
420 parent.setColumns(Lists.newArrayList());
421 }
422
423
424 sources.stream()
425 .filter(Objects::nonNull)
426 .forEach(source -> {
427 ExtractionProductColumn target = existingItems.remove(source.getColumnName());
428 boolean isNew = (target == null);
429 if (isNew) {
430 target = new ExtractionProductColumn();
431 }
432 target.setTable(parent);
433 Beans.copyProperties(source, target);
434 target.setLabel(StringUtils.underscoreToChangeCase(source.getColumnName()));
435
436 if (isNew) {
437 em.persist(target);
438 source.setId(target.getId());
439 } else {
440 em.merge(target);
441 }
442
443 if (isNew) parent.getColumns().add(target);
444 });
445
446 getSession().flush();
447
448
449
450 sources.stream()
451 .filter(Objects::nonNull)
452 .forEach(source -> saveProductTableValues(source.getValues(), source.getId()));
453
454 getSession().flush();
455
456
457
458 if (MapUtils.isNotEmpty(existingItems)) {
459 parent.getColumns().removeAll(existingItems.values());
460 existingItems.values().forEach(em::remove);
461 }
462
463 getSession().flush();
464
465 }
466 }
467
468 protected void saveProductTableValues(List<String> sources, int columnId) {
469 ExtractionProductColumn parent = get(ExtractionProductColumn.class, columnId);
470
471 final EntityManager em = getEntityManager();
472 if (CollectionUtils.isEmpty(sources)) {
473 if (parent.getValues() != null) {
474 List<ExtractionProductValue> toRemove = ImmutableList.copyOf(parent.getValues());
475 parent.getValues().clear();
476 toRemove.forEach(em::remove);
477 }
478 } else {
479 Map<String, ExtractionProductValue> existingItems = Beans.splitByProperty(
480 Beans.getList(parent.getValues()),
481 ExtractionProductValue.Fields.LABEL);
482 if (parent.getValues() == null) {
483 parent.setValues(Lists.newArrayList());
484 }
485
486
487 sources.stream()
488 .filter(StringUtils::isNotBlank)
489 .forEach(valueLabel -> {
490 ExtractionProductValue target = existingItems.remove(valueLabel);
491 boolean isNew = (target == null);
492 if (isNew) {
493 target = new ExtractionProductValue();
494 }
495 target.setColumn(parent);
496 target.setLabel(valueLabel);
497 if (isNew) {
498 em.persist(target);
499 } else {
500 em.merge(target);
501 }
502
503 if (isNew) parent.getValues().add(target);
504 });
505
506 getSession().flush();
507
508
509
510 if (MapUtils.isNotEmpty(existingItems)) {
511 parent.getValues().removeAll(existingItems.values());
512 existingItems.values().forEach(em::remove);
513 }
514
515 }
516 }
517
518 protected ExtractionProductVO toProductVO(ExtractionProduct source, ProductFetchOptions fetchOptions) {
519 ExtractionProductVOction/ExtractionProductVO.html#ExtractionProductVO">ExtractionProductVO target = new ExtractionProductVO();
520 Beans.copyProperties(source, target);
521
522
523 if (source.getStatus() != null) {
524 target.setStatusId(source.getStatus().getId());
525 }
526
527
528 if (fetchOptions == null || fetchOptions.isWithTables()) {
529 if (CollectionUtils.isNotEmpty(source.getTables())) {
530 List<ExtractionProductTableVO> tables = source.getTables().stream()
531 .map(t -> toProductTableVO(t, fetchOptions))
532 .collect(Collectors.toList());
533 target.setTables(tables);
534 }
535 }
536
537
538 if (fetchOptions == null || fetchOptions.isWithStratum()) {
539 if (CollectionUtils.isNotEmpty(source.getStratum())) {
540 List<ExtractionProductStrataVO> stratum = source.getStratum().stream()
541 .map(t -> toProductStrataVO(t))
542 .collect(Collectors.toList());
543 target.setStratum(stratum);
544 }
545 }
546
547
548 if (fetchOptions == null || fetchOptions.isWithRecorderDepartment()) {
549 target.setRecorderDepartment(departmentDao.toDepartmentVO(source.getRecorderDepartment()));
550 }
551 if (fetchOptions == null || fetchOptions.isWithRecorderPerson()) {
552 target.setRecorderPerson(personDao.toPersonVO(source.getRecorderPerson()));
553 }
554
555 return target;
556 }
557
558 protected ExtractionProductTableVO toProductTableVO(ExtractionProductTable source, ProductFetchOptions fetchOptions) {
559 ExtractionProductTableVO/ExtractionProductTableVO.html#ExtractionProductTableVO">ExtractionProductTableVO target = new ExtractionProductTableVO();
560 Beans.copyProperties(source, target);
561
562
563 if (source.getProduct() != null) {
564 target.setProductId(source.getProduct().getId());
565 }
566
567
568 if (source.getStatus() != null) {
569 target.setStatusId(source.getStatus().getId());
570 }
571
572
573 if (fetchOptions == null || fetchOptions.isWithColumns()) {
574 if (CollectionUtils.isNotEmpty(source.getColumns())) {
575 target.setColumns(source.getColumns().stream()
576 .map(c -> toColumnVO(c, fetchOptions))
577 .collect(Collectors.toList()));
578 }
579 }
580
581 return target;
582
583 }
584
585 protected ExtractionProductStrataVO toProductStrataVO(ExtractionProductStrata source) {
586 ExtractionProductStrataVOExtractionProductStrataVO.html#ExtractionProductStrataVO">ExtractionProductStrataVO target = new ExtractionProductStrataVO();
587 Beans.copyProperties(source, target);
588
589
590 if (source.getProduct() != null) {
591 target.setProductId(source.getProduct().getId());
592 }
593
594
595 if (source.getStatus() != null) {
596 target.setStatusId(source.getStatus().getId());
597 }
598
599
600 if (source.getTable() != null) {
601 target.setSheetName(source.getTable().getLabel());
602 }
603
604
605 if (source.getTimeColumn() != null) {
606 target.setTimeColumnName(source.getTimeColumn().getColumnName());
607 }
608 if (source.getSpaceColumn() != null) {
609 target.setSpaceColumnName(source.getSpaceColumn().getColumnName());
610 }
611 if (source.getTechColumn() != null) {
612 target.setTechColumnName(source.getTechColumn().getColumnName());
613 }
614 if (source.getAggColumn() != null) {
615 target.setAggColumnName(source.getAggColumn().getColumnName());
616 }
617
618 return target;
619
620 }
621
622 protected List<String> toColumnValues(ExtractionProductColumn source) {
623 if (source == null || CollectionUtils.isEmpty(source.getValues())) return null;
624 return source.getValues().stream()
625 .map(ExtractionProductValue::getLabel)
626 .collect(Collectors.toList());
627 }
628
629 protected ExtractionProductColumnVO toColumnVO(ExtractionProductColumn source, ProductFetchOptions fetchOptions) {
630 ExtractionProductColumnVOExtractionProductColumnVO.html#ExtractionProductColumnVO">ExtractionProductColumnVO target = new ExtractionProductColumnVO();
631 Beans.copyProperties(source, target);
632
633 if (fetchOptions == null || fetchOptions.isWithColumnValues()) {
634 target.setValues(toColumnValues(source));
635 }
636 return target;
637 }
638
639 protected ExtractionProductColumn findColumnByName(ExtractionProductTable table, String columnName) {
640 if (StringUtils.isBlank(columnName)) return null;
641 return table.getColumns().stream()
642 .filter(c -> columnName.equalsIgnoreCase(c.getColumnName()))
643 .findFirst().orElse(null);
644 }
645
646 }