1 package fr.ifremer.tutti.persistence.service;
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.ArrayListMultimap;
27 import com.google.common.collect.Lists;
28 import fr.ifremer.adagio.core.dao.administration.programStrategy.Program;
29 import fr.ifremer.adagio.core.dao.administration.user.DepartmentId;
30 import fr.ifremer.adagio.core.dao.administration.user.DepartmentImpl;
31 import fr.ifremer.adagio.core.dao.administration.user.PersonId;
32 import fr.ifremer.adagio.core.dao.administration.user.PersonImpl;
33 import fr.ifremer.adagio.core.dao.data.batch.Batch;
34 import fr.ifremer.adagio.core.dao.data.batch.CatchBatch;
35 import fr.ifremer.adagio.core.dao.data.batch.SortingBatch;
36 import fr.ifremer.adagio.core.dao.data.operation.FishingOperationImpl;
37 import fr.ifremer.adagio.core.dao.data.sample.Sample;
38 import fr.ifremer.adagio.core.dao.referential.QualityFlagCode;
39 import fr.ifremer.adagio.core.dao.referential.QualityFlagImpl;
40 import fr.ifremer.adagio.core.dao.referential.pmfm.Matrix;
41 import fr.ifremer.adagio.core.dao.referential.pmfm.MatrixId;
42 import fr.ifremer.adagio.core.dao.referential.pmfm.MatrixImpl;
43 import fr.ifremer.adagio.core.dao.referential.taxon.ReferenceTaxonImpl;
44 import fr.ifremer.tutti.persistence.entities.CaracteristicMap;
45 import fr.ifremer.tutti.persistence.entities.TuttiEntities;
46 import fr.ifremer.tutti.persistence.entities.data.CopyIndividualObservationMode;
47 import fr.ifremer.tutti.persistence.entities.data.FishingOperation;
48 import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatch;
49 import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatchs;
50 import fr.ifremer.tutti.persistence.entities.referential.Caracteristic;
51 import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValue;
52 import fr.ifremer.tutti.persistence.entities.referential.Species;
53 import fr.ifremer.tutti.persistence.service.referential.CaracteristicPersistenceService;
54 import fr.ifremer.tutti.persistence.service.referential.SpeciesPersistenceService;
55 import fr.ifremer.tutti.persistence.service.util.BatchPersistenceHelper;
56 import fr.ifremer.tutti.persistence.service.util.SamplePersistenceHelper;
57 import fr.ifremer.tutti.persistence.service.util.SynchronizationStatusHelper;
58 import org.apache.commons.collections4.CollectionUtils;
59 import org.apache.commons.lang3.StringUtils;
60 import org.apache.commons.logging.Log;
61 import org.apache.commons.logging.LogFactory;
62 import org.hibernate.type.IntegerType;
63 import org.springframework.stereotype.Service;
64
65 import javax.annotation.Resource;
66 import java.io.Serializable;
67 import java.util.ArrayList;
68 import java.util.Collection;
69 import java.util.Collections;
70 import java.util.Iterator;
71 import java.util.LinkedHashSet;
72 import java.util.List;
73 import java.util.Map;
74 import java.util.Objects;
75 import java.util.Set;
76 import java.util.stream.Collectors;
77
78
79
80
81
82 @Service("individualObservationBatchPersistenceService")
83 public class IndividualObservationBatchPersistenceServiceImpl extends AbstractPersistenceService implements IndividualObservationBatchPersistenceService {
84
85
86 private static final Log log =
87 LogFactory.getLog(IndividualObservationBatchPersistenceServiceImpl.class);
88
89 @Resource(name = "caracteristicPersistenceService")
90 private CaracteristicPersistenceService caracteristicService;
91
92 @Resource(name = "speciesPersistenceService")
93 private SpeciesPersistenceService speciesService;
94
95 @Resource(name = "attachmentPersistenceService")
96 protected AttachmentPersistenceService attachmentPersistenceService;
97
98 @Resource(name = "samplePersistenceHelper")
99 protected SamplePersistenceHelper samplePersistenceHelper;
100
101 @Resource(name = "batchPersistenceHelper")
102 protected BatchPersistenceHelper batchHelper;
103
104 @Resource(name = "synchronizationStatusHelper")
105 protected SynchronizationStatusHelper synchronizationStatusHelper;
106
107 @Resource(name = "fishingOperationPersistenceService")
108 protected FishingOperationPersistenceService fishingOperationPersistenceService;
109
110 protected Caracteristic sampleCodeCaracteristic;
111
112 @Override
113 public void init() {
114 super.init();
115
116 sampleCodeCaracteristic = caracteristicService.getSampleCodeCaracteristic();
117 }
118
119 @Override
120 public List<IndividualObservationBatch> getAllIndividualObservationBatchsForCruise(Integer cruiseId) {
121 Preconditions.checkNotNull(cruiseId);
122
123 List<IndividualObservationBatch> result = new ArrayList<>();
124 List<Integer> allFishingOperationIds = fishingOperationPersistenceService.getAllFishingOperationIds(cruiseId);
125 allFishingOperationIds.forEach(fishingOperationId -> {
126
127 Iterator<Object[]> list = queryList("allFishingOperationSamplesWithBatch",
128 "fishingOperationId", IntegerType.INSTANCE, fishingOperationId);
129
130 List<IndividualObservationBatch> resultForFishingOperation = toBeanListWithFishingOperation(list, fishingOperationId);
131 result.addAll(resultForFishingOperation);
132
133 });
134 return Collections.unmodifiableList(result);
135
136 }
137
138 @Override
139 public boolean isSamplingCodeAvailable(Integer cruiseId, Integer referenceTaxonId, String samplingCodeSuffix) {
140
141 Preconditions.checkNotNull(cruiseId);
142 Preconditions.checkNotNull(referenceTaxonId);
143 Preconditions.checkNotNull(samplingCodeSuffix);
144
145 List<Integer> allFishingOperationIds = fishingOperationPersistenceService.getAllFishingOperationIds(cruiseId);
146 for (Integer fishingOperationId : allFishingOperationIds) {
147
148 Iterator<Integer> list = queryListTyped("allFishingOperationSampleIdsWithBatchForSpecies",
149 "fishingOperationId", IntegerType.INSTANCE, fishingOperationId,
150 "referenceTaxonId", IntegerType.INSTANCE, referenceTaxonId);
151
152 while (list.hasNext()) {
153
154 Integer sampleId = list.next();
155
156 Serializable sampleMeasurementValue = samplePersistenceHelper.getSampleMeasurementValue(sampleId, sampleCodeCaracteristic);
157 if (sampleMeasurementValue != null) {
158
159 if (sampleMeasurementValue.toString().endsWith(samplingCodeSuffix)) {
160
161
162 return false;
163
164 }
165
166 }
167
168 }
169
170 }
171
172
173 return true;
174
175 }
176
177 @Override
178 public List<IndividualObservationBatch> getAllIndividualObservationBatchsForFishingOperation(Integer fishingOperationId) {
179 Preconditions.checkNotNull(fishingOperationId);
180
181 Iterator<Object[]> list = queryList("allFishingOperationSamplesWithBatch",
182 "fishingOperationId", IntegerType.INSTANCE, fishingOperationId);
183
184 List<IndividualObservationBatch> result = toBeanListWithFishingOperation(list, fishingOperationId);
185
186 return Collections.unmodifiableList(result);
187
188 }
189
190 @Override
191 public List<IndividualObservationBatch> getAllIndividualObservationBatchsForBatch(Integer batchId) {
192 Preconditions.checkNotNull(batchId);
193
194 Iterator<Object[]> list = queryList("allFishingOperationSamplesForBatch",
195 "batchId", IntegerType.INSTANCE, batchId);
196
197 List<IndividualObservationBatch> result = toBeanList(list);
198 return Collections.unmodifiableList(result);
199
200 }
201
202 @Override
203 public List<IndividualObservationBatch> createIndividualObservationBatches(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) {
204
205 Preconditions.checkNotNull(individualObservations);
206
207
208 List<IndividualObservationBatch> notNullObservations = individualObservations.stream()
209 .filter(source -> source.getLengthStepCaracteristic() != null)
210 .collect(Collectors.toList());
211
212 ArrayListMultimap<Integer, IndividualObservationBatch> individualObservationBatchesByBatchId = ArrayListMultimap.create();
213
214 notNullObservations.forEach(individualObservationBatch -> individualObservationBatchesByBatchId.put(individualObservationBatch.getBatchId(), individualObservationBatch));
215
216 for (Map.Entry<Integer, Collection<IndividualObservationBatch>> entry : individualObservationBatchesByBatchId.asMap().entrySet()) {
217
218 Integer speciesBatchId = entry.getKey();
219 Collection<IndividualObservationBatch> individualObservationBatches = entry.getValue();
220
221 createOrSave(speciesBatchId, individualObservationBatches);
222
223 }
224
225 return Collections.unmodifiableList(notNullObservations);
226
227 }
228
229 @Override
230 public List<IndividualObservationBatch> saveBatchIndividualObservation(Integer speciesBatchId,
231 List<IndividualObservationBatch> individualObservation) {
232
233 Preconditions.checkNotNull(speciesBatchId);
234 Preconditions.checkNotNull(individualObservation);
235
236
237 List<IndividualObservationBatch> notNullObservations = individualObservation.stream()
238 .filter(source -> source.getLengthStepCaracteristic() != null)
239 .collect(Collectors.toList());
240
241 createOrSave(speciesBatchId, individualObservation);
242
243 return Collections.unmodifiableList(notNullObservations);
244
245 }
246
247 @Override
248 public void deleteAllIndividualObservationsForFishingOperation(Integer fishingOperationId) {
249
250 Set<Integer> individualObservationIds = getAllIndividualObservationBatchIds(fishingOperationId);
251
252 if (log.isInfoEnabled()) {
253 log.info(String.format("[Fishing Operation: %d] Delete %d individual observations.", fishingOperationId, individualObservationIds.size()));
254 }
255
256 individualObservationIds.forEach(samplePersistenceHelper::deleteSample);
257
258 }
259
260 @Override
261 public void deleteAllIndividualObservationsForBatch(Integer speciesBatchId) {
262
263 Set<Integer> allSpeciesBatchIds = batchHelper.getBatchIds(speciesBatchId);
264
265 for (Integer aSpeciesBatchId : allSpeciesBatchIds) {
266
267 Set<Integer> individualObservationIds = getAllIndividualObservationBatchIdsForBatch(aSpeciesBatchId);
268
269 if (log.isInfoEnabled()) {
270 log.info(String.format("[Species batch: %d] Delete %d individual observations.", aSpeciesBatchId, individualObservationIds.size()));
271 }
272 individualObservationIds.forEach(samplePersistenceHelper::deleteSample);
273
274 }
275
276 }
277
278
279
280
281
282 protected void beanToEntity(IndividualObservationBatch source, Sample target, Batch batch) {
283
284
285 fr.ifremer.adagio.core.dao.data.operation.FishingOperation fishingOperation;
286
287 fishingOperation = load(FishingOperationImpl.class, source.getFishingOperation().getIdAsInt());
288
289
290 target.setFishingOperation(fishingOperation);
291
292
293 target.setBatch(batch);
294 target.setFishingOperation(fishingOperation);
295
296 if (TuttiEntities.isNew(source)) {
297
298
299 String label = batch.getId() + "_" + source.getSpecies().getReferenceTaxonId();
300 target.setLabel(label);
301
302
303 Matrix matrix = load(MatrixImpl.class, MatrixId.PRODUCE_BATCH.getValue());
304 target.setMatrix(matrix);
305
306
307 target.setIndividualCount((short) 1);
308
309
310 target.setQualityFlag(load(QualityFlagImpl.class, QualityFlagCode.NOTQUALIFIED.getValue()));
311
312
313 if (target.getSampleDate() == null) {
314 target.setSampleDate(fishingOperation.getFishingStartDateTime());
315 }
316
317
318 target.setCreationDate(fishingOperation.getFishingStartDateTime());
319
320
321 target.setRecorderDepartment(load(DepartmentImpl.class, DepartmentId.UNKNOWN_RECORDER_DEPARTMENT.getValue()));
322
323
324 target.setRecorderPerson(load(PersonImpl.class, PersonId.UNKNOWN_RECORDER_PERSON.getValue()));
325
326
327 Program program = fishingOperation.getFishingTrip().getProgram();
328 target.setProgram(program);
329 }
330
331
332 target.setId(source.getIdAsInt());
333
334
335 target.setComments(source.getComment());
336
337
338 Species species = source.getSpecies();
339 Integer referenceTaxonId = species.getReferenceTaxonId();
340 target.setReferenceTaxon(load(ReferenceTaxonImpl.class, referenceTaxonId));
341
342
343
344
345
346
347
348 CaracteristicMap caracteristics = samplePersistenceHelper.extractCommonSampleCaracteristics(source);
349
350 CopyIndividualObservationMode copyIndividualObservationMode = source.getCopyIndividualObservationMode();
351 Objects.requireNonNull(copyIndividualObservationMode, "Any individual observation requires a copy mode");
352
353 Caracteristic copyIndividualObservationModeCaracteristic = caracteristicService.getCopyIndividualObservationModeCaracteristic();
354 CaracteristicQualitativeValue qualitativeValue = copyIndividualObservationMode.getQualitativeValue(copyIndividualObservationModeCaracteristic);
355 caracteristics.put(copyIndividualObservationModeCaracteristic, qualitativeValue);
356
357 if (StringUtils.isNotBlank(source.getSamplingCode())) {
358 Caracteristic sampleCodeCaracteristic = caracteristicService.getSampleCodeCaracteristic();
359 caracteristics.put(sampleCodeCaracteristic, source.getSamplingCode());
360 }
361
362 samplePersistenceHelper.setSampleMeasurements(target, caracteristics);
363
364 }
365
366 protected IndividualObservationBatch toBean(Object[] source) {
367
368 IndividualObservationBatch batch = IndividualObservationBatchs.newIndividualObservationBatch();
369
370 int colIndex = 0;
371
372
373 batch.setId((Integer) source[colIndex++]);
374
375
376 batch.setBatchId((Integer) source[colIndex++]);
377
378
379 Integer taxonId = (Integer) source[colIndex++];
380 Species species = speciesService.getSpeciesByReferenceTaxonId(taxonId);
381 batch.setSpecies(species);
382
383
384 batch.setComment((String) source[colIndex]);
385
386
387 batch.setSynchronizationStatus((String) source[colIndex]);
388
389
390 batch.setCaracteristics(new CaracteristicMap());
391
392
393 fillSampleMeasurements(batch);
394
395 return batch;
396
397 }
398
399 protected List<IndividualObservationBatch> toBeanList(Iterator<Object[]> list) {
400
401 List<IndividualObservationBatch> result = Lists.newArrayList();
402
403 while (list.hasNext()) {
404
405 IndividualObservationBatch individualObservationBatch = toBean(list.next());
406 result.add(individualObservationBatch);
407
408 }
409
410 return result;
411
412 }
413
414 protected List<IndividualObservationBatch> toBeanListWithFishingOperation(Iterator<Object[]> list, Integer fishingOperationId) {
415
416 List<IndividualObservationBatch> result = toBeanList(list);
417 FishingOperation fishingOperation = fishingOperationPersistenceService.getFishingOperation(fishingOperationId);
418 result.forEach(individualObservationBatch -> individualObservationBatch.setFishingOperation(fishingOperation));
419 return result;
420 }
421
422 protected Batch getBatch(Integer operationId) {
423 Preconditions.checkNotNull(operationId);
424
425 return batchHelper.getRootCatchBatchByFishingOperationId(operationId, false);
426 }
427
428 protected void fillSampleMeasurements(IndividualObservationBatch batch) {
429
430 samplePersistenceHelper.loadSampleMeasurements(batch);
431
432 CaracteristicMap caracteristics = batch.getCaracteristics();
433
434 Caracteristic copyIndividualObservationModeCaracteristic = caracteristicService.getCopyIndividualObservationModeCaracteristic();
435
436 CaracteristicQualitativeValue copyIndividualObservationMode = caracteristics.removeQualitativeValue(copyIndividualObservationModeCaracteristic);
437 if (copyIndividualObservationMode != null) {
438 batch.setCopyIndividualObservationMode(CopyIndividualObservationMode.valueOf(copyIndividualObservationMode.getIdAsInt()));
439 } else {
440 batch.setCopyIndividualObservationMode(CopyIndividualObservationMode.NOTHING);
441 }
442
443 Caracteristic sampleCodeCaracteristic = caracteristicService.getSampleCodeCaracteristic();
444 String sampleCode = caracteristics.removeStringValue(sampleCodeCaracteristic);
445 batch.setSamplingCode(sampleCode);
446 }
447
448 protected Set<Integer> getAllIndividualObservationBatchIdsForBatch(Integer batchId) {
449
450 Preconditions.checkNotNull(batchId);
451 Iterator<Integer> list = queryListTyped("allFishingOperationSampleIdsForBatch",
452 "batchId", IntegerType.INSTANCE, batchId);
453
454 return toIds(list);
455
456 }
457
458 protected Set<Integer> getAllIndividualObservationBatchIds(Integer fishingOperationId) {
459
460 Preconditions.checkNotNull(fishingOperationId);
461
462 Iterator<Integer> list = queryListTyped("allFishingOperationSampleIds",
463 "fishingOperationId", IntegerType.INSTANCE, fishingOperationId);
464
465 return toIds(list);
466
467 }
468
469 protected Set<Integer> toIds(Iterator<Integer> list) {
470
471 Set<Integer> result = new LinkedHashSet<>();
472
473 while (list.hasNext()) {
474 Integer id = list.next();
475 result.add(id);
476 }
477 return result;
478
479 }
480
481 protected void createOrSave(Integer speciesBatchId, Collection<IndividualObservationBatch> notNullObservations) {
482
483 CatchBatch catchBatch = batchHelper.getRootCatchBatchByBatchId(speciesBatchId);
484
485 if (catchBatch == null) {
486
487 throw new IllegalStateException("Can't find catch batch from batchId: " + speciesBatchId);
488
489 }
490
491
492 synchronizationStatusHelper.setDirty(catchBatch);
493
494
495 SortingBatch batch = batchHelper.getSortingBatchById(catchBatch, speciesBatchId);
496 if (batch == null) {
497
498 throw new IllegalStateException("Can't find batch from batchId: " + speciesBatchId);
499
500 }
501
502
503 Set<Integer> notUpdatedChildIds = getAllIndividualObservationBatchIdsForBatch(speciesBatchId);
504
505 for (IndividualObservationBatch source : notNullObservations) {
506
507 Sample target;
508 if (TuttiEntities.isNew(source)) {
509
510
511 target = Sample.Factory.newInstance();
512
513
514 beanToEntity(source, target, batch);
515
516
517 samplePersistenceHelper.create(target);
518 source.setId(String.valueOf(target.getId()));
519
520 if (log.isInfoEnabled()) {
521 log.info("Create individual observation (" + source.getRankOrder() + "): " + target.getId());
522 }
523
524 } else {
525
526
527 target = samplePersistenceHelper.load(source.getIdAsInt());
528
529
530 beanToEntity(source, target, batch);
531 samplePersistenceHelper.update(target);
532
533
534 notUpdatedChildIds.remove(target.getId());
535
536 if (log.isInfoEnabled()) {
537 log.info("Update individual observation (" + source.getRankOrder() + "): " + target.getId());
538 }
539 }
540
541 synchronizationStatusHelper.setDirty(source);
542
543 }
544
545 if (CollectionUtils.isNotEmpty(notUpdatedChildIds)) {
546
547
548 for (Integer observationId : notUpdatedChildIds) {
549
550 if (log.isInfoEnabled()) {
551 log.info("Remove obsolete individual observation: " + observationId);
552 }
553 samplePersistenceHelper.deleteSample(observationId);
554 }
555
556 }
557
558 }
559 }