1 package fr.ifremer.tutti.service.sampling;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import com.google.common.base.MoreObjects;
28 import com.google.common.collect.HashMultimap;
29 import com.google.common.collect.Multimap;
30 import fr.ifremer.tutti.persistence.entities.TuttiEntities;
31 import fr.ifremer.tutti.persistence.entities.data.FishingOperation;
32 import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatch;
33 import fr.ifremer.tutti.persistence.entities.protocol.CalcifiedPiecesSamplingDefinition;
34 import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocol;
35 import fr.ifremer.tutti.persistence.entities.protocol.Zone;
36 import fr.ifremer.tutti.persistence.entities.protocol.Zones;
37 import fr.ifremer.tutti.persistence.entities.referential.Caracteristic;
38 import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValue;
39 import fr.ifremer.tutti.persistence.entities.referential.Species;
40 import fr.ifremer.tutti.persistence.entities.referential.TuttiLocation;
41 import fr.ifremer.tutti.service.cruise.CruiseCacheAble;
42 import java.util.Collection;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Objects;
47 import java.util.Optional;
48 import java.util.stream.IntStream;
49 import org.apache.commons.logging.Log;
50 import org.apache.commons.logging.LogFactory;
51
52 import static fr.ifremer.tutti.service.sampling.CruiseSamplingInternalCache.addPrefixKey;
53
54
55
56
57
58 public class CruiseSamplingCache implements CruiseCacheAble {
59
60
61 private static final Log log = LogFactory.getLog(CruiseSamplingCache.class);
62
63
64
65
66 private final CruiseSamplingInternalCache cruiseCache = new CruiseSamplingInternalCache();
67
68
69
70 private final CruiseSamplingInternalCache zoneCache = new CruiseSamplingInternalCache();
71
72
73
74 private final CruiseSamplingInternalCache fishingOperationCache = new CruiseSamplingInternalCache();
75
76
77
78 private final Multimap<Zone, Integer> locationIdsPerZone;
79
80
81
82 private final Multimap<Integer, CalcifiedPiecesSamplingDefinition> cpsDefinitionsBySpecies = HashMultimap.create();
83
84
85
86 private final Map<Integer, Caracteristic> maturityCaracteristicBySpecies = new HashMap<>();
87
88
89
90 private final Multimap<String, String> matureStatesByMaturityCracteristic = HashMultimap.create();
91
92
93
94 private final Caracteristic sexCaracteristic;
95
96
97
98 private final Map<Integer, CaracteristicQualitativeValue> sexQualitativeValues;
99
100
101
102 private boolean loading;
103
104 public CruiseSamplingCache(TuttiProtocol protocol, Caracteristic sexCaracteristic, Collection<Caracteristic> maturityCaracteristics) {
105 this.sexCaracteristic = sexCaracteristic;
106 this.sexQualitativeValues = TuttiEntities.splitByIdAsInt(sexCaracteristic.getQualitativeValue());
107
108 locationIdsPerZone = HashMultimap.create();
109 protocol.getZone().forEach(zone -> locationIdsPerZone.putAll(zone, Zones.getAllLocationIds(zone)));
110
111 Map<String, Caracteristic> maturityCaracteristicsById = TuttiEntities.splitById(maturityCaracteristics);
112
113 protocol.getSpecies().forEach(speciesProtocol -> {
114 cpsDefinitionsBySpecies.putAll(speciesProtocol.getSpeciesReferenceTaxonId(),
115 speciesProtocol.getCalcifiedPiecesSamplingDefinition());
116 maturityCaracteristicBySpecies.put(speciesProtocol.getSpeciesReferenceTaxonId(),
117 maturityCaracteristicsById.get(speciesProtocol.getMaturityPmfmId()));
118 });
119
120
121
122 protocol.getBenthos().forEach(speciesProtocol -> {
123 cpsDefinitionsBySpecies.putAll(speciesProtocol.getSpeciesReferenceTaxonId(),
124 speciesProtocol.getCalcifiedPiecesSamplingDefinition());
125 maturityCaracteristicBySpecies.put(speciesProtocol.getSpeciesReferenceTaxonId(),
126 maturityCaracteristicsById.get(speciesProtocol.getMaturityPmfmId()));
127 });
128
129 protocol.getMaturityCaracteristics().forEach(mc -> matureStatesByMaturityCracteristic.putAll(mc.getId(), mc.getMatureStateIds()));
130 }
131
132 public boolean isLoading() {
133 return loading;
134 }
135
136 public void setLoading(boolean loading) {
137 this.loading = loading;
138 }
139
140 @Override
141 public void addFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) {
142
143 addIndividualObservations(fishingOperation, individualObservations);
144
145 }
146
147 @Override
148 public void addIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) {
149
150 Objects.requireNonNull(fishingOperation);
151 Objects.requireNonNull(individualObservations);
152
153 Optional<Zone> optionalZone = tryFindZone(fishingOperation);
154 if (!optionalZone.isPresent()) {
155
156
157 return;
158
159 }
160
161 Zone zone = optionalZone.get();
162
163 setLoading(true);
164
165 try {
166
167 for (IndividualObservationBatch individualObservationBatch : individualObservations) {
168
169 Optional<CalcifiedPiecesSamplingDefinition> optionalCalcifiedPiecesSamplingDefinition =
170 tryToFindCalcifiedPiecesSamplingDefinition(individualObservationBatch);
171
172 if (!optionalCalcifiedPiecesSamplingDefinition.isPresent()) {
173
174
175 continue;
176 }
177
178 Species species = individualObservationBatch.getSpecies();
179 Objects.requireNonNull(species);
180
181
182 Float lengthStep = individualObservationBatch.getSize();
183 Objects.requireNonNull(lengthStep);
184
185 Boolean maturity = getMaturity(individualObservationBatch);
186
187
188 int lengthStepInMm = individualObservationBatch.getLengthStepCaracteristic().getLengthStepInMm(lengthStep);
189
190 CaracteristicQualitativeValue gender = individualObservationBatch.getCaracteristics().getQualitativeValue(sexCaracteristic);
191
192 IndividualObservationSamplingContext individualObservationSamplingContext =
193 createContext(fishingOperation.getIdAsInt(),
194 species,
195 zone,
196 optionalCalcifiedPiecesSamplingDefinition.get(),
197 lengthStepInMm,
198 maturity,
199 gender);
200
201 addIndividualObservation(individualObservationSamplingContext, individualObservationBatch.getSamplingCode() != null);
202
203 }
204
205 } finally {
206
207 setLoading(false);
208
209 }
210
211 }
212
213 @Override
214 public void removeIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) {
215
216 Objects.requireNonNull(fishingOperation);
217 Objects.requireNonNull(individualObservations);
218
219 Optional<Zone> optionalZone = tryFindZone(fishingOperation);
220 if (!optionalZone.isPresent()) {
221
222
223 return;
224
225 }
226
227 Zone zone = optionalZone.get();
228
229 setLoading(true);
230
231 try {
232
233 for (IndividualObservationBatch individualObservationBatch : individualObservations) {
234
235 Optional<CalcifiedPiecesSamplingDefinition> optionalCalcifiedPiecesSamplingDefinition =
236 tryToFindCalcifiedPiecesSamplingDefinition(individualObservationBatch);
237
238 if (!optionalCalcifiedPiecesSamplingDefinition.isPresent()) {
239
240
241 continue;
242 }
243
244 Species species = individualObservationBatch.getSpecies();
245 Objects.requireNonNull(species);
246
247 Boolean maturity = getMaturity(individualObservationBatch);
248
249 Objects.requireNonNull(individualObservationBatch.getSize());
250 float lengthStep = individualObservationBatch.getSize();
251
252
253
254 int lengthStepInMm = individualObservationBatch.getLengthStepCaracteristic().getLengthStepInMm(lengthStep);
255
256
257 CaracteristicQualitativeValue gender = individualObservationBatch.getCaracteristics().getQualitativeValue(sexCaracteristic);
258
259 IndividualObservationSamplingContext individualObservationSamplingContext =
260 createContext(fishingOperation.getIdAsInt(),
261 species,
262 zone,
263 optionalCalcifiedPiecesSamplingDefinition.get(),
264 lengthStepInMm,
265 maturity,
266 gender);
267
268 removeIndividualObservation(individualObservationSamplingContext, individualObservationBatch.getSamplingCode() != null);
269
270 }
271
272 } finally {
273
274 setLoading(false);
275
276 }
277
278 }
279
280 @Override
281 public void removeFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) {
282
283 Objects.requireNonNull(fishingOperation);
284 Objects.requireNonNull(individualObservations);
285
286 Optional<Zone> optionalZone = tryFindZone(fishingOperation);
287 if (!optionalZone.isPresent()) {
288
289
290 return;
291
292 }
293
294 Zone zone = optionalZone.get();
295
296
297 String fishingOperationId = fishingOperation.getId();
298
299 if (log.isInfoEnabled()) {
300 log.info("Removing fishing operation: " + fishingOperation + " from " + this);
301 }
302
303
304
305 String keyPrefix = CruiseSamplingInternalCache.addPrefixKey(fishingOperationId, "");
306 int keyPrefixLength = keyPrefix.length();
307
308 fishingOperationCache.getKeys()
309 .stream()
310 .filter(key -> key.startsWith(keyPrefix))
311 .forEach(fishingOperationSamplingKey -> {
312
313 CruiseSamplingInternalCache.SamplingData samplingData = fishingOperationCache.getSamplingData(fishingOperationSamplingKey);
314
315 if (log.isInfoEnabled()) {
316 log.info("Found " + fishingOperationSamplingKey + " to remove from fishing operation cache (" + samplingData + ").");
317 }
318
319 int individualObservationCount = samplingData.getIndividualObservationCount();
320 int samplingCount = samplingData.getSamplingCount();
321
322 String cruiseSamplingKey = fishingOperationSamplingKey.substring(keyPrefixLength);
323 cruiseCache.remove(cruiseSamplingKey, individualObservationCount, samplingCount);
324
325 String zoneSamplingKey = createZoneSamplingKey(cruiseSamplingKey, zone);
326 zoneCache.remove(zoneSamplingKey, individualObservationCount, samplingCount);
327
328 fishingOperationCache.remove(fishingOperationSamplingKey, individualObservationCount, samplingCount);
329
330 });
331
332 printInfos("After removing " + fishingOperation);
333
334 cleanEmptyEntries();
335
336 printInfos("After cleanEmptyEntries");
337
338 if (log.isInfoEnabled()) {
339 log.info(fishingOperation + " removed from fishingOperationCache: " + fishingOperationCache.size());
340 log.info(fishingOperation + " removed from cruiseCache: " + cruiseCache.size());
341 log.info(fishingOperation + " removed from zoneCache: " + zoneCache.size());
342 log.info(fishingOperation + " removed from " + this);
343 }
344
345 }
346
347 @Override
348 public void close() {
349
350 if (log.isInfoEnabled()) {
351 log.info("Closing cruise sampling cache.");
352 }
353 cruiseCache.close();
354 zoneCache.close();
355 fishingOperationCache.close();
356 locationIdsPerZone.clear();
357 cpsDefinitionsBySpecies.clear();
358 maturityCaracteristicBySpecies.clear();
359 matureStatesByMaturityCracteristic.clear();
360 }
361
362 @Override
363 public String toString() {
364 return MoreObjects.toStringHelper(this)
365 .add("cruiseCache", cruiseCache.size())
366 .add("zoneCache", zoneCache.size())
367 .add("fishingOperationCache", fishingOperationCache.size())
368 .toString();
369 }
370
371 public IndividualObservationSamplingStatus getIndividualObservationSamplingStatus(IndividualObservationSamplingCacheRequest request) throws SizeNotDefinedOnIndividualObservationException, ZoneNotDefinedOnFishingOperationException, CalcifiedPiecesSamplingAlgorithmEntryNotFoundException {
372
373 Objects.requireNonNull(request);
374
375 Species species = request.getSpecies();
376 Objects.requireNonNull(species);
377
378 Integer lengthStep = request.getLengthClass();
379 if (lengthStep == null) {
380
381 throw new SizeNotDefinedOnIndividualObservationException(request);
382 }
383
384 FishingOperation fishingOperation = request.getFishingOperation();
385 Objects.requireNonNull(fishingOperation);
386
387 Optional<Zone> optionalZone = tryFindZone(fishingOperation);
388 if (!optionalZone.isPresent()) {
389
390 throw new ZoneNotDefinedOnFishingOperationException(request);
391 }
392
393 CaracteristicQualitativeValue gender = request.getGender();
394 Boolean maturity = getMaturity(request);
395
396 Optional<CalcifiedPiecesSamplingDefinition> optionalCalcifiedPiecesSamplingDefinition =
397 tryToFindCalcifiedPiecesSamplingDefinition(species, lengthStep, maturity, gender);
398
399 if (!optionalCalcifiedPiecesSamplingDefinition.isPresent()) {
400
401 throw new CalcifiedPiecesSamplingAlgorithmEntryNotFoundException(request);
402 }
403
404 IndividualObservationSamplingContext context = createContext(fishingOperation.getIdAsInt(),
405 species,
406 optionalZone.get(),
407 optionalCalcifiedPiecesSamplingDefinition.get(),
408 lengthStep,
409 maturity,
410 gender);
411
412 String cruiseSamplingKey = context.getCruiseSamplingKey();
413 CruiseSamplingInternalCache.SamplingData cruiseSamplingData = cruiseCache.getOrCreateSamplingData(cruiseSamplingKey);
414
415 String zoneSamplingKey = context.getZoneSamplingKey();
416 CruiseSamplingInternalCache.SamplingData zoneSamplingData = zoneCache.getOrCreateSamplingData(zoneSamplingKey);
417
418 String fishingOperationSamplingKey = context.getFishingOperationSamplingKey();
419 CruiseSamplingInternalCache.SamplingData fishingOperationSamplingData = fishingOperationCache.getOrCreateSamplingData(fishingOperationSamplingKey);
420
421
422 boolean computeSampling = !request.withSamplingCode();
423
424 return new IndividualObservationSamplingStatus(context, computeSampling, cruiseSamplingData, zoneSamplingData, fishingOperationSamplingData);
425
426 }
427
428 public void addIndividualObservation(IndividualObservationSamplingCacheRequest request) {
429
430 IndividualObservationSamplingContext individualObservationSamplingContext = getIndividualObservationSamplingContext(request);
431
432 if (individualObservationSamplingContext != null) {
433
434 addIndividualObservation(individualObservationSamplingContext, request.withSamplingCode());
435
436 }
437
438 }
439
440 public void removeIndividualObservation(IndividualObservationSamplingCacheRequest request) {
441
442 IndividualObservationSamplingContext individualObservationSamplingContext = getIndividualObservationSamplingContext(request);
443
444 if (individualObservationSamplingContext != null) {
445
446 removeIndividualObservation(individualObservationSamplingContext, request.withSamplingCode());
447
448 }
449
450 }
451
452 public void addSampling(IndividualObservationSamplingCacheRequest request) {
453
454 IndividualObservationSamplingContext individualObservationSamplingContext = getIndividualObservationSamplingContext(request);
455
456 if (individualObservationSamplingContext != null) {
457
458 addSampling(individualObservationSamplingContext);
459
460 }
461
462 }
463
464 public void removeSampling(IndividualObservationSamplingCacheRequest request) {
465
466 IndividualObservationSamplingContext individualObservationSamplingContext = getIndividualObservationSamplingContext(request);
467
468 if (individualObservationSamplingContext != null) {
469
470 removeSampling(individualObservationSamplingContext);
471
472 }
473
474 }
475
476 public boolean isZoneChanged(FishingOperation operation1, FishingOperation operation2) {
477
478 Optional<Zone> optionalZone1 = tryFindZone(operation1);
479 Optional<Zone> optionalZone2 = tryFindZone(operation2);
480 return !Objects.equals(optionalZone1, optionalZone2);
481
482 }
483
484 public List<CacheExtractedKey> getSamplingNumbers(Map<String, Species> speciesById) {
485 List<CacheExtractedKey> result = cruiseCache.getSamplingNumbers(speciesById, sexQualitativeValues);
486 result.forEach(key -> {
487 Optional<CalcifiedPiecesSamplingDefinition> cpsDef = tryToFindCalcifiedPiecesSamplingDefinition(key.getSpecies(), key.getLengthStep(), key.getMaturity(), key.getSex());
488 if (cpsDef.isPresent()) {
489 key.setMaxByLengthStep(cpsDef.get().getMaxByLenghtStep());
490 }
491 });
492 return result;
493 }
494
495 public Optional<Zone> tryFindZone(FishingOperation operation) {
496 Optional<Zone> result;
497 if (operation.getSubStrata() != null) {
498 result = tryFindZone(operation.getSubStrata());
499 } else if (operation.getStrata() != null) {
500 result = tryFindZone(operation.getStrata());
501 } else {
502 result = Optional.empty();
503 }
504 return result;
505 }
506
507 public boolean isSpeciesDefined(Species species) {
508 return cpsDefinitionsBySpecies.containsKey(species.getReferenceTaxonId());
509 }
510
511 private Optional<Zone> tryFindZone(TuttiLocation location) {
512
513
514
515
516
517
518 Integer locationId = location.getIdAsInt();
519 return locationIdsPerZone.keySet()
520 .stream()
521 .filter(zone -> locationIdsPerZone.containsEntry(zone, locationId))
522 .findFirst();
523
524 }
525
526 private Boolean getMaturity(IndividualObservationSamplingCacheRequest samplingCacheRequest) {
527 Boolean maturity = samplingCacheRequest.getForcedMaturity();
528 if (maturity == null && samplingCacheRequest.withMaturity()) {
529 Caracteristic maturityCaracteristic = maturityCaracteristicBySpecies.get(samplingCacheRequest.getSpecies().getReferenceTaxonId());
530 if (maturityCaracteristic != null) {
531 CaracteristicQualitativeValue maturityQualitativeValue = samplingCacheRequest.getMaturity();
532 maturity = matureStatesByMaturityCracteristic.containsEntry(maturityCaracteristic.getId(), maturityQualitativeValue.getId());
533 }
534 }
535
536 return maturity;
537 }
538
539
540
541
542
543
544
545 private Boolean getMaturity(IndividualObservationBatch individualObservationBatch) {
546 Boolean maturity = null;
547 Caracteristic maturityCaracteristic = maturityCaracteristicBySpecies.get(individualObservationBatch.getSpecies().getReferenceTaxonId());
548
549 if (maturityCaracteristic != null) {
550 CaracteristicQualitativeValue qualitativeValue = individualObservationBatch.getCaracteristics().getQualitativeValue(maturityCaracteristic);
551
552 if (qualitativeValue != null) {
553 maturity = matureStatesByMaturityCracteristic.containsEntry(maturityCaracteristic.getId(), qualitativeValue.getId());
554 }
555 }
556 return maturity;
557 }
558
559 private String createCruiseSamplingKey(Species species,
560 CaracteristicQualitativeValue gender,
561 Boolean maturity,
562 int lengthStep) {
563 return CruiseSamplingInternalCache.createSamplingKey(species, gender, maturity, lengthStep);
564 }
565
566 private String createZoneSamplingKey(String cruiseSamplingKey, Zone zone) {
567 return addPrefixKey((zone == null ? "" : zone.getId()), cruiseSamplingKey);
568 }
569
570 private String createFishingOperationSamplingKey(String cruiseSamplingKey, int fishingOperationId) {
571 return addPrefixKey(fishingOperationId, cruiseSamplingKey);
572 }
573
574 private void addIndividualObservation(IndividualObservationSamplingContext individualObservationSamplingContext, boolean addSampling) {
575
576 Objects.requireNonNull(individualObservationSamplingContext);
577
578 String cruiseSamplingKey = individualObservationSamplingContext.getCruiseSamplingKey();
579 CruiseSamplingInternalCache.SamplingData cruiseSamplingData = cruiseCache.addOneIndividualObservation(cruiseSamplingKey);
580
581 String zoneSamplingKey = individualObservationSamplingContext.getZoneSamplingKey();
582 CruiseSamplingInternalCache.SamplingData zoneSamplingData = zoneCache.addOneIndividualObservation(zoneSamplingKey);
583
584 String fishingOperationSamplingKey = individualObservationSamplingContext.getFishingOperationSamplingKey();
585 CruiseSamplingInternalCache.SamplingData fishingOperationSamplingData = fishingOperationCache.addOneIndividualObservation(fishingOperationSamplingKey);
586
587 if (log.isInfoEnabled()) {
588 log.info(getLogMessage("add individual observation ",
589 cruiseSamplingKey,
590 zoneSamplingKey,
591 fishingOperationSamplingKey,
592 cruiseSamplingData,
593 zoneSamplingData,
594 fishingOperationSamplingData));
595 }
596
597 if (addSampling) {
598
599 addSampling(individualObservationSamplingContext);
600
601 }
602
603 }
604
605 private void removeIndividualObservation(IndividualObservationSamplingContext individualObservationSamplingContext, boolean removeSampling) {
606
607 Objects.requireNonNull(individualObservationSamplingContext);
608
609 String cruiseSamplingKey = individualObservationSamplingContext.getCruiseSamplingKey();
610 CruiseSamplingInternalCache.SamplingData cruiseSamplingData = cruiseCache.removeOneIndividualObservation(cruiseSamplingKey);
611
612 String zoneSamplingKey = individualObservationSamplingContext.getZoneSamplingKey();
613 CruiseSamplingInternalCache.SamplingData zoneSamplingData = zoneCache.removeOneIndividualObservation(zoneSamplingKey);
614
615 String fishingOperationSamplingKey = individualObservationSamplingContext.getFishingOperationSamplingKey();
616 CruiseSamplingInternalCache.SamplingData fishingOperationSamplingData = fishingOperationCache.removeOneIndividualObservation(fishingOperationSamplingKey);
617
618 if (log.isInfoEnabled()) {
619 log.info(getLogMessage("remove individual observation ",
620 cruiseSamplingKey,
621 zoneSamplingKey,
622 fishingOperationSamplingKey,
623 cruiseSamplingData,
624 zoneSamplingData,
625 fishingOperationSamplingData));
626 }
627
628 if (removeSampling) {
629
630 removeSampling(individualObservationSamplingContext);
631
632 }
633
634 }
635
636 private void addSampling(IndividualObservationSamplingContext individualObservationSamplingContext) {
637
638 Objects.requireNonNull(individualObservationSamplingContext);
639
640 String cruiseSamplingKey = individualObservationSamplingContext.getCruiseSamplingKey();
641 CruiseSamplingInternalCache.SamplingData cruiseSamplingData = cruiseCache.addOneSampling(cruiseSamplingKey);
642
643 String zoneSamplingKey = individualObservationSamplingContext.getZoneSamplingKey();
644 CruiseSamplingInternalCache.SamplingData zoneSamplingData = zoneCache.addOneSampling(zoneSamplingKey);
645
646 String fishingOperationSamplingKey = individualObservationSamplingContext.getFishingOperationSamplingKey();
647 CruiseSamplingInternalCache.SamplingData fishingOperationSamplingData = fishingOperationCache.addOneSampling(fishingOperationSamplingKey);
648
649 if (log.isInfoEnabled()) {
650 log.info(getLogMessage("add sampling ",
651 cruiseSamplingKey,
652 zoneSamplingKey,
653 fishingOperationSamplingKey,
654 cruiseSamplingData,
655 zoneSamplingData,
656 fishingOperationSamplingData));
657 }
658
659 }
660
661 private void removeSampling(IndividualObservationSamplingContext individualObservationSamplingContext) {
662
663 Objects.requireNonNull(individualObservationSamplingContext);
664
665 String cruiseSamplingKey = individualObservationSamplingContext.getCruiseSamplingKey();
666 CruiseSamplingInternalCache.SamplingData cruiseSamplingData = cruiseCache.removeOneSampling(cruiseSamplingKey);
667
668 String zoneSamplingKey = individualObservationSamplingContext.getZoneSamplingKey();
669 CruiseSamplingInternalCache.SamplingData zoneSamplingData = zoneCache.removeOneSampling(zoneSamplingKey);
670
671 String fishingOperationSamplingKey = individualObservationSamplingContext.getFishingOperationSamplingKey();
672 CruiseSamplingInternalCache.SamplingData fishingOperationSamplingData = fishingOperationCache.removeOneSampling(fishingOperationSamplingKey);
673
674 if (log.isInfoEnabled()) {
675 log.info(getLogMessage("remove sampling ",
676 cruiseSamplingKey,
677 zoneSamplingKey,
678 fishingOperationSamplingKey,
679 cruiseSamplingData,
680 zoneSamplingData,
681 fishingOperationSamplingData));
682 }
683
684 }
685
686 private IndividualObservationSamplingContext getIndividualObservationSamplingContext(IndividualObservationSamplingCacheRequest request) {
687
688 Objects.requireNonNull(request);
689
690 FishingOperation fishingOperation = request.getFishingOperation();
691 Objects.requireNonNull(fishingOperation);
692
693 Optional<Zone> optionalZone = tryFindZone(fishingOperation);
694 if (!optionalZone.isPresent()) {
695
696 if (log.isInfoEnabled()) {
697 log.info("Do not record sampling in cache, fishing operation has no matching zone.");
698 }
699 return null;
700 }
701
702 Integer lengthStep = request.getLengthClass();
703 Objects.requireNonNull(lengthStep);
704
705 Species species = request.getSpecies();
706 Objects.requireNonNull(species);
707
708 Boolean maturity = getMaturity(request);
709 CaracteristicQualitativeValue gender = request.getGender();
710
711 Optional<CalcifiedPiecesSamplingDefinition> optionalCalcifiedPiecesSamplingDefinition =
712 tryToFindCalcifiedPiecesSamplingDefinition(species, lengthStep, maturity, gender);
713
714 if (!optionalCalcifiedPiecesSamplingDefinition.isPresent()) {
715
716 if (log.isInfoEnabled()) {
717 log.info("Do not record sampling in cache, no definition matched.");
718 }
719 return null;
720 }
721
722 return createContext(fishingOperation.getIdAsInt(),
723 species,
724 optionalZone.get(),
725 optionalCalcifiedPiecesSamplingDefinition.get(),
726 lengthStep,
727 maturity,
728 gender);
729
730 }
731
732 private IndividualObservationSamplingContext createContext(int fishingOperationId,
733 Species species,
734 Zone zone,
735 CalcifiedPiecesSamplingDefinition calcifiedPiecesSamplingDefinition,
736 Integer lengthStep,
737 Boolean maturity,
738 CaracteristicQualitativeValue gender) {
739
740 String cruiseSamplingKey = createCruiseSamplingKey(species, gender, maturity, lengthStep);
741 String zoneSamplingKey = createZoneSamplingKey(cruiseSamplingKey, zone);
742 String fishingOperationSamplingKey = createFishingOperationSamplingKey(cruiseSamplingKey, fishingOperationId);
743
744 return new IndividualObservationSamplingContext(species,
745 lengthStep,
746 maturity,
747 gender,
748 calcifiedPiecesSamplingDefinition,
749 zone,
750 cruiseSamplingKey,
751 zoneSamplingKey,
752 fishingOperationSamplingKey);
753
754 }
755
756 private Optional<CalcifiedPiecesSamplingDefinition> tryToFindCalcifiedPiecesSamplingDefinition(IndividualObservationBatch individualObservationBatch) {
757
758 Species species = individualObservationBatch.getSpecies();
759 Objects.requireNonNull(species);
760
761 Float lengthStep = individualObservationBatch.getSize();
762
763 Optional<CalcifiedPiecesSamplingDefinition> result;
764 if (lengthStep == null) {
765
766
767 result = Optional.empty();
768
769 } else {
770
771 Boolean maturity = getMaturity(individualObservationBatch);
772
773
774 int lengthStepInMm = individualObservationBatch.getLengthStepCaracteristic().getLengthStepInMm(lengthStep);
775
776
777 CaracteristicQualitativeValue gender = individualObservationBatch.getCaracteristics().getQualitativeValue(sexCaracteristic);
778
779 result = tryToFindCalcifiedPiecesSamplingDefinition(species, lengthStepInMm, maturity, gender);
780
781 }
782
783 return result;
784
785 }
786
787 private Optional<CalcifiedPiecesSamplingDefinition> tryToFindCalcifiedPiecesSamplingDefinition(Species species,
788 int lengthStep,
789 Boolean maturity,
790 CaracteristicQualitativeValue gender) {
791
792 Collection<CalcifiedPiecesSamplingDefinition> cpsDefinitions = cpsDefinitionsBySpecies.get(species.getReferenceTaxonId());
793
794 CalcifiedPiecesSamplingDefinition result = null;
795
796 if (cpsDefinitions == null) {
797
798 if (log.isInfoEnabled()) {
799 log.info(species + " not found in any calcified pieces sampling definitions");
800 }
801
802 } else {
803
804
805
806
807
808
809
810
811
812 Optional<CalcifiedPiecesSamplingDefinition> optionalDefinition =
813 cpsDefinitions.stream()
814 .filter(cpsDef -> (cpsDef.getMaturity() == null || Objects.equals(cpsDef.getMaturity(), maturity))
815 && lengthStep >= cpsDef.getMinSize()
816 && (cpsDef.getMaxSize() == null || lengthStep <= cpsDef.getMaxSize()))
817 .findFirst();
818
819 if (!optionalDefinition.isPresent()) {
820
821 if (log.isInfoEnabled()) {
822 log.info(species + " - maturity " + maturity + " length step " + lengthStep + " not found in calcified pieces sampling definitions");
823 }
824
825 } else {
826
827 result = optionalDefinition.get();
828
829 if (result.getSamplingInterval() == 0) {
830
831 if (log.isInfoEnabled()) {
832 log.info("Can't use definition with no sampling interval: " + result);
833 }
834 result = null;
835
836 } else if ((result.isSex() && gender == null)) {
837
838 if (log.isInfoEnabled()) {
839 log.info("Can't use definition (sex is required, but none was given): " + result);
840 }
841 result = null;
842
843 } else {
844
845 if (log.isInfoEnabled()) {
846 log.info("Found matching definition: " + result);
847 }
848
849 }
850
851 }
852
853 }
854
855 return Optional.ofNullable(result);
856
857 }
858
859 private String getLogMessage(String prefix,
860 String cruiseSamplingKey,
861 String zoneSamplingKey,
862 String fishingOperationSamplingKey,
863 CruiseSamplingInternalCache.SamplingData cruiseSamplingData,
864 CruiseSamplingInternalCache.SamplingData zoneSamplingData,
865 CruiseSamplingInternalCache.SamplingData fishingOperationSamplingData) {
866
867 int maxSize = IntStream
868 .builder()
869 .add(cruiseSamplingKey.length())
870 .add(zoneSamplingKey.length())
871 .add(fishingOperationSamplingKey.length())
872 .build()
873 .max()
874 .orElseGet(() -> 0);
875
876 return prefix
877 + "\n[cruise " + (String.format("%1$" + maxSize + "s", cruiseSamplingKey).replaceAll(" ", ".")) + "] → " + cruiseSamplingData
878 + "\n[zone " + (String.format("%1$" + maxSize + "s", zoneSamplingKey).replaceAll(" ", ".")) + "] → " + zoneSamplingData
879 + "\n[fishing operation" + (String.format("%1$" + maxSize + "s", fishingOperationSamplingKey).replaceAll(" ", ".")) + "] → " + fishingOperationSamplingData;
880
881 }
882
883 private void cleanEmptyEntries() {
884 cruiseCache.cleanEmptyEntries();
885 zoneCache.cleanEmptyEntries();
886 fishingOperationCache.cleanEmptyEntries();
887 }
888
889 public void printInfos(String message) {
890
891 if (log.isInfoEnabled()) {
892
893 String cruiseCacheInfos = cruiseCache.toStringVerbose();
894 String zoneCacheInfos = zoneCache.toStringVerbose();
895 String fishingOperationCacheInfos = fishingOperationCache.toStringVerbose();
896
897 StringBuilder stringBuilder = new StringBuilder(message);
898 stringBuilder.append("\nCruise cache: ").append(cruiseCacheInfos);
899 stringBuilder.append("\nZone cache: ").append(zoneCacheInfos);
900 stringBuilder.append("\nFishing operation cache: ").append(fishingOperationCacheInfos);
901
902 if (log.isInfoEnabled()) {
903 log.info(stringBuilder.toString());
904 }
905 }
906 }
907
908 }