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 com.google.common.collect.Lists;
27 import com.google.common.collect.Multimap;
28 import net.sumaris.core.dao.referential.ReferentialDao;
29 import net.sumaris.core.dao.referential.taxon.TaxonNameDao;
30 import net.sumaris.core.model.administration.programStrategy.PmfmStrategy;
31 import net.sumaris.core.model.administration.user.Department;
32 import net.sumaris.core.model.data.Batch;
33 import net.sumaris.core.model.data.Operation;
34 import net.sumaris.core.model.referential.QualityFlag;
35 import net.sumaris.core.model.referential.taxon.ReferenceTaxon;
36 import net.sumaris.core.model.referential.taxon.TaxonGroup;
37 import net.sumaris.core.model.referential.taxon.TaxonName;
38 import net.sumaris.core.util.Beans;
39 import net.sumaris.core.vo.administration.user.DepartmentVO;
40 import net.sumaris.core.vo.data.BatchVO;
41 import net.sumaris.core.vo.data.OperationVO;
42 import net.sumaris.core.vo.referential.ReferentialVO;
43 import net.sumaris.core.vo.referential.TaxonNameVO;
44 import org.apache.commons.collections4.CollectionUtils;
45 import org.apache.commons.collections4.MapUtils;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.beans.factory.annotation.Autowired;
49 import org.springframework.dao.DataIntegrityViolationException;
50 import org.springframework.stereotype.Repository;
51
52 import javax.persistence.EntityManager;
53 import javax.persistence.criteria.CriteriaBuilder;
54 import javax.persistence.criteria.CriteriaQuery;
55 import javax.persistence.criteria.ParameterExpression;
56 import javax.persistence.criteria.Root;
57 import java.sql.Timestamp;
58 import java.util.Collection;
59 import java.util.List;
60 import java.util.Map;
61 import java.util.Objects;
62 import java.util.stream.Collectors;
63 import java.util.stream.Stream;
64
65 @Repository("batchDao")
66 public class BatchDaoImpl extends BaseDataDaoImpl implements BatchDao {
67
68
69 private static final Logger log =
70 LoggerFactory.getLogger(BatchDaoImpl.class);
71
72 @Autowired
73 private ReferentialDao referentialDao;
74
75 @Autowired
76 private TaxonNameDao taxonNameDao;
77
78 @Override
79 public List<BatchVO> getAllByOperationId(int operationId) {
80 CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
81 CriteriaQuery<Batch> query = cb.createQuery(Batch.class);
82 Root<Batch> root = query.from(Batch.class);
83
84 query.select(root);
85
86 ParameterExpression<Integer> tripIdParam = cb.parameter(Integer.class);
87
88 query.where(cb.equal(root.get(Batch.Fields.OPERATION).get(Batch.Fields.ID), tripIdParam));
89
90
91 query.orderBy(cb.asc(root.get(PmfmStrategy.Fields.RANK_ORDER)));
92
93 return toBatchVOs(getEntityManager().createQuery(query)
94 .setParameter(tripIdParam, operationId).getResultList(), false);
95 }
96
97 @Override
98 public BatchVO get(int id) {
99 Batch entity = get(Batch.class, id);
100 return toBatchVO(entity, false);
101 }
102
103 @Override
104 public List<BatchVO> saveByOperationId(int operationId, List<BatchVO> sources) {
105
106
107 Operation parent = get(Operation.class, operationId);
108 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
109
110
111
112 final Multimap<Integer, Batch> sourcesByHashCode = Beans.splitByNotUniqueProperty(Beans.getList(parent.getBatches()), Batch.Fields.HASH);
113 final Multimap<String, Batch> sourcesByLabelMap = Beans.splitByNotUniqueProperty(Beans.getList(parent.getBatches()), Batch.Fields.LABEL);
114 final Map<Integer, Batch> sourcesIdsToRemove = Beans.splitById(Beans.getList(parent.getBatches()));
115
116
117 sources.forEach(source -> {
118 source.setOperationId(operationId);
119
120 Batch existingBatch = null;
121 if (source.getId() != null) {
122 existingBatch = sourcesIdsToRemove.remove(source.getId());
123 }
124
125 else {
126
127 Collection<Batch> existingBatchs = sourcesByHashCode.get(source.hashCode());
128
129 if (CollectionUtils.isEmpty(existingBatchs)) {
130 existingBatchs = sourcesByLabelMap.get(source.getLabel());
131 }
132
133 if (CollectionUtils.size(existingBatchs) == 1) {
134 existingBatch = existingBatchs.iterator().next();
135 sourcesIdsToRemove.remove(existingBatch.getId());
136 source.setId(existingBatch.getId());
137 }
138 }
139 optimizedSave(source, existingBatch, false, newUpdateDate, false);
140 });
141
142
143 if (MapUtils.isNotEmpty(sourcesIdsToRemove)) {
144 sourcesIdsToRemove.values().forEach(this::delete);
145 }
146
147
148 sources.forEach(batch -> {
149 if (batch.getParent() != null) {
150 batch.setParentId(batch.getParent().getId());
151 batch.setParent(null);
152 }
153 });
154
155 entityManager.flush();
156 entityManager.clear();
157
158 return sources;
159 }
160
161
162 @Override
163 public BatchVOef="../../../../../net/sumaris/core/vo/data/BatchVO.html#BatchVO">BatchVO save(BatchVO source) {
164 Preconditions.checkNotNull(source);
165
166 EntityManager entityManager = getEntityManager();
167 Batch entity = null;
168 if (source.getId() != null) {
169 entity = get(Batch.class, source.getId());
170 }
171 boolean isNew = (entity == null);
172 if (isNew) {
173 entity = new Batch();
174 }
175
176 if (!isNew) {
177
178
179
180
181
182
183 }
184
185
186 copySomeFieldsFromOperation(source);
187
188
189 batchVOToEntity(source, entity, true);
190
191
192 Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
193 entity.setUpdateDate(newUpdateDate);
194
195
196 if (isNew) {
197 entityManager.persist(entity);
198 source.setId(entity.getId());
199 } else {
200 entityManager.merge(entity);
201 }
202
203
204 source.setUpdateDate(newUpdateDate);
205
206 entityManager.flush();
207 entityManager.clear();
208
209 return source;
210 }
211
212 @Override
213 public void delete(int id) {
214
215 log.debug(String.format("Deleting batch {id=%s}...", id));
216 delete(Batch.class, id);
217 }
218
219 @Override
220 public BatchVO toBatchVO(Batch source) {
221 return toBatchVO(source, true);
222 }
223
224 @Override
225 public List<BatchVO> toFlatList(final BatchVO source) {
226 List<BatchVO> result = Lists.newArrayList();
227 fillListFromTree(result, source);
228 return result;
229 }
230
231
232
233 protected BatchVO/../../../net/sumaris/core/vo/data/BatchVO.html#BatchVO">BatchVO optimizedSave(BatchVO source,
234 Batch entity,
235 boolean checkUpdateDate,
236 Timestamp newUpdateDate,
237 boolean flush) {
238 Preconditions.checkNotNull(source);
239
240 EntityManager entityManager = getEntityManager();
241 if (entity == null && source.getId() != null) {
242 entity = get(Batch.class, source.getId());
243 }
244 boolean isNew = (entity == null);
245 if (isNew) {
246 entity = new Batch();
247 }
248
249 if (!isNew && checkUpdateDate) {
250
251
252 checkUpdateDateForUpdate(source, entity);
253
254
255
256 }
257
258
259 copySomeFieldsFromOperation(source);
260
261
262 batchVOToEntity(source, entity, true);
263
264
265 entity.setUpdateDate(newUpdateDate);
266
267
268 if (isNew) {
269 entityManager.persist(entity);
270 source.setId(entity.getId());
271 } else {
272 entityManager.merge(entity);
273 }
274
275
276 source.setUpdateDate(newUpdateDate);
277
278 if (flush) {
279 entityManager.flush();
280 entityManager.clear();
281 }
282
283 return source;
284 }
285
286 protected BatchVO toBatchVO(Batch source, boolean allFields) {
287
288 if (source == null) return null;
289
290 BatchVOatchVO.html#BatchVO">BatchVO target = new BatchVO();
291
292 Beans.copyProperties(source, target);
293
294
295 if (source.getTaxonGroup() != null) {
296 ReferentialVO taxonGroup = referentialDao.toReferentialVO(source.getTaxonGroup());
297 target.setTaxonGroup(taxonGroup);
298 }
299
300
301 if (source.getReferenceTaxon() != null) {
302 TaxonNameVO taxonName = taxonNameDao.getTaxonNameReferent(source.getReferenceTaxon().getId());
303 target.setTaxonName(taxonName);
304 }
305
306
307 if (source.getParent() != null) {
308 target.setParentId(source.getParent().getId());
309 }
310
311
312 if (source.getOperation() != null) {
313 target.setOperationId(source.getOperation().getId());
314 }
315
316
317 if (allFields) {
318
319 DepartmentVO recorderDepartment = referentialDao.toTypedVO(source.getRecorderDepartment(), DepartmentVO.class).orElse(null);
320 target.setRecorderDepartment(recorderDepartment);
321 }
322
323 return target;
324 }
325
326 protected void copySomeFieldsFromOperation(BatchVO target) {
327 OperationVO source = target.getOperation();
328 if (source == null) return;
329
330 target.setRecorderDepartment(source.getRecorderDepartment());
331 }
332
333 protected List<BatchVO> toBatchVOs(List<Batch> source, boolean allFields) {
334 return this.toBatchVOs(source.stream(), allFields);
335 }
336
337 protected List<BatchVO> toBatchVOs(Stream<Batch> source, boolean allFields) {
338 return source.map(s -> this.toBatchVO(s, allFields))
339 .filter(Objects::nonNull)
340 .collect(Collectors.toList());
341 }
342
343 protected void batchVOToEntity(BatchVO source, Batch target, boolean copyIfNull) {
344
345 Beans.copyProperties(source, target);
346
347
348 if (copyIfNull || source.getTaxonGroup() != null) {
349 if (source.getTaxonGroup() == null || source.getTaxonGroup().getId() == null) {
350 target.setTaxonGroup(null);
351 }
352 else {
353 target.setTaxonGroup(load(TaxonGroup.class, source.getTaxonGroup().getId()));
354 }
355 }
356
357
358 if (copyIfNull || source.getTaxonName() != null) {
359 if (source.getTaxonName() == null || source.getTaxonName().getId() == null) {
360 target.setReferenceTaxon(null);
361 }
362 else {
363 if (source.getTaxonName().getReferenceTaxonId() != null) {
364 target.setReferenceTaxon(load(ReferenceTaxon.class, source.getTaxonName().getReferenceTaxonId()));
365 }
366 else {
367
368 TaxonName taxonname = get(TaxonName.class, source.getTaxonName().getId());
369 if (taxonname != null) {
370 target.setReferenceTaxon(taxonname.getReferenceTaxon());
371 }
372 else {
373 throw new DataIntegrityViolationException("Invalid batch: unknown taxon name with id "+ source.getTaxonName().getId());
374 }
375 }
376 }
377 }
378
379 Integer parentId = (source.getParent() != null ? source.getParent().getId() : source.getParentId());
380 Integer opeId = source.getOperationId() != null ? source.getOperationId() : (source.getOperation() != null ? source.getOperation().getId() : null);
381
382
383 if (copyIfNull || (parentId != null)) {
384 if (parentId == null) {
385 target.setParent(null);
386 }
387 else {
388 Batch parent = load(Batch.class, parentId);
389 target.setParent(parent);
390
391
392 opeId = parent.getOperation().getId();
393 }
394 }
395
396
397 if (copyIfNull || (opeId != null)) {
398 if (opeId == null) {
399 target.setOperation(null);
400 }
401 else {
402 target.setOperation(load(Operation.class, opeId));
403 }
404 }
405
406
407 if (copyIfNull || source.getRecorderDepartment() != null) {
408 if (source.getRecorderDepartment() == null || source.getRecorderDepartment().getId() == null) {
409 target.setRecorderDepartment(null);
410 }
411 else {
412 target.setRecorderDepartment(load(Department.class, source.getRecorderDepartment().getId()));
413 }
414 }
415
416
417 if (copyIfNull || source.getQualityFlagId() != null) {
418 if (source.getQualityFlagId() == null) {
419 target.setQualityFlag(load(QualityFlag.class, config.getDefaultQualityFlagId()));
420 }
421 else {
422 target.setQualityFlag(load(QualityFlag.class, source.getQualityFlagId()));
423 }
424 }
425
426
427 target.setHash(source.hashCode());
428 }
429
430 protected void fillListFromTree(final List<BatchVO> result, final BatchVO source) {
431
432 result.add(source);
433
434 if (CollectionUtils.isNotEmpty(source.getChildren())) {
435 source.getChildren().forEach(child -> {
436 child.setParentId(source.getId());
437 fillListFromTree(result, child);
438 });
439 }
440
441
442 source.setParent(null);
443 source.setChildren(null);
444 }
445 }