1 package fr.ifremer.tutti.service.catches;
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.collect.Lists;
26 import com.google.common.collect.Maps;
27 import fr.ifremer.tutti.persistence.InvalidBatchModelException;
28 import fr.ifremer.tutti.persistence.ProgressionModel;
29 import fr.ifremer.tutti.persistence.entities.data.AccidentalBatch;
30 import fr.ifremer.tutti.persistence.entities.data.BatchContainer;
31 import fr.ifremer.tutti.persistence.entities.data.CatchBatch;
32 import fr.ifremer.tutti.persistence.entities.data.Cruise;
33 import fr.ifremer.tutti.persistence.entities.data.FishingOperation;
34 import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatch;
35 import fr.ifremer.tutti.persistence.entities.data.MarineLitterBatch;
36 import fr.ifremer.tutti.persistence.entities.data.SpeciesBatch;
37 import fr.ifremer.tutti.persistence.entities.data.SpeciesBatchFrequency;
38 import fr.ifremer.tutti.persistence.entities.protocol.SpeciesProtocol;
39 import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocol;
40 import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocols;
41 import fr.ifremer.tutti.persistence.entities.referential.Species;
42 import fr.ifremer.tutti.service.AbstractTuttiService;
43 import fr.ifremer.tutti.service.DecoratorService;
44 import fr.ifremer.tutti.service.PersistenceService;
45 import fr.ifremer.tutti.service.TuttiDataContext;
46 import fr.ifremer.tutti.service.TuttiServiceContext;
47 import fr.ifremer.tutti.service.ValidationService;
48 import org.apache.commons.collections4.CollectionUtils;
49 import org.apache.commons.collections4.MapUtils;
50 import org.apache.commons.io.FileUtils;
51 import org.apache.commons.logging.Log;
52 import org.apache.commons.logging.LogFactory;
53 import org.nuiton.decorator.Decorator;
54 import org.nuiton.jaxx.application.ApplicationBusinessException;
55 import org.nuiton.jaxx.application.ApplicationTechnicalException;
56 import org.nuiton.validator.NuitonValidatorResult;
57 import org.nuiton.validator.NuitonValidatorScope;
58
59 import java.io.File;
60 import java.io.IOException;
61 import java.util.ArrayList;
62 import java.util.LinkedHashMap;
63 import java.util.LinkedHashSet;
64 import java.util.List;
65 import java.util.Map;
66 import java.util.Set;
67 import java.util.stream.Collectors;
68
69 import static org.nuiton.i18n.I18n.t;
70
71
72
73
74
75
76
77 public class ValidateCruiseOperationsService extends AbstractTuttiService {
78
79 private static final Log log = LogFactory.getLog(ValidateCruiseOperationsService.class);
80
81 protected PersistenceService persistenceService;
82
83 protected ValidationService validationService;
84
85 protected WeightComputingService weightComputingService;
86
87 protected DecoratorService decoratorService;
88
89 @Override
90 public void setServiceContext(TuttiServiceContext context) {
91 super.setServiceContext(context);
92 persistenceService = getService(PersistenceService.class);
93 validationService = getService(ValidationService.class);
94 weightComputingService = getService(WeightComputingService.class);
95 decoratorService = getService(DecoratorService.class);
96 }
97
98
99
100
101
102
103 public NuitonValidatorResult validateCruise(ProgressionModel progressionModel, Integer cruiseId) {
104
105 progressionModel.increments(t("tutti.service.validateCruise.cruise.loading", cruiseId));
106 Cruise cruise = persistenceService.getCruise(cruiseId);
107
108 Decorator<Cruise> decorator = decoratorService.getDecoratorByType(Cruise.class);
109 progressionModel.increments(t("tutti.service.validateCruise.cruise.check", cruiseId, decorator.toString(cruise)));
110
111 return validationService.validateValidateCruise(cruise);
112
113 }
114
115
116
117
118
119
120 public LinkedHashMap<FishingOperation, NuitonValidatorResult> validateOperations(ProgressionModel progressionModel, List<Integer> operationIds) {
121
122 LinkedHashMap<FishingOperation, NuitonValidatorResult> result = new LinkedHashMap<>();
123
124 Decorator<FishingOperation> decorator = decoratorService.getDecoratorByType(FishingOperation.class);
125 for (Integer operationId : operationIds) {
126
127 progressionModel.increments(t("tutti.service.validateCruise.operations.loading", operationId));
128 FishingOperation operation = persistenceService.getFishingOperation(operationId);
129
130 progressionModel.increments(t("tutti.service.validateCruise.operations.check", operationId, decorator.toString(operation)));
131 NuitonValidatorResult validator = validationService.validateValidateFishingOperation(operation);
132
133 checkOperation(operation, validator);
134 result.put(operation, validator);
135
136 }
137
138 return result;
139
140 }
141
142
143
144
145
146
147 public NuitonValidatorResult validateCruiseCruise(Cruise cruise) {
148 return validationService.validateValidateCruise(cruise);
149 }
150
151
152
153
154
155
156 public NuitonValidatorResult validateCruiseOperation(FishingOperation operation) {
157 NuitonValidatorResult validator = validationService.validateValidateFishingOperation(operation);
158 checkOperation(operation, validator);
159 return validator;
160 }
161
162
163
164
165
166
167 public NuitonValidatorResult validateCruiseOperation(CatchBatch catches) {
168 FishingOperation operation = persistenceService.getFishingOperation(catches.getFishingOperation().getIdAsInt());
169 NuitonValidatorResult validator = validationService.validateValidateFishingOperation(operation);
170
171 checkOperation(operation, catches, validator);
172 return validator;
173 }
174
175
176
177
178
179 public void exportValidationResults(File file, Map<FishingOperation, NuitonValidatorResult> validationResults) {
180 try {
181 List<String> lines = Lists.newArrayList();
182 for (FishingOperation operation : validationResults.keySet()) {
183 lines.addAll(getExportLines(operation, validationResults.get(operation)));
184 lines.add("");
185 }
186 FileUtils.writeLines(file, lines);
187
188 } catch (IOException e) {
189 throw new ApplicationTechnicalException(t("tutti.service.validateCruise.exportResult.error", file));
190 }
191 }
192
193
194
195
196
197
198 public void exportValidationResult(File file, FishingOperation operation, NuitonValidatorResult validationResult) {
199 try {
200 List<String> lines = getExportLines(operation, validationResult);
201
202 FileUtils.writeLines(file, lines);
203
204 } catch (IOException e) {
205 throw new ApplicationTechnicalException(t("tutti.service.validateCruise.exportResult.error", file));
206 }
207 }
208
209
210
211
212
213
214
215
216
217
218
219 protected void checkOperation(FishingOperation fishingOperation, NuitonValidatorResult validator) {
220
221 Integer fishingOperationId = fishingOperation.getIdAsInt();
222
223 boolean withCatchBatch =
224 persistenceService.isFishingOperationWithCatchBatch(
225 fishingOperationId);
226
227 if (!withCatchBatch) {
228 if (log.isWarnEnabled()) {
229 log.warn("Skip fishing operation " + fishingOperation +
230 " since no catchBatch associated.");
231 }
232 Map<String, List<String>> errorMap = Maps.newHashMap();
233 errorMap.put("catches", Lists.newArrayList(t("tutti.validator.warning.fishingOperation.batch.notFound")));
234 validator.addMessagesForScope(NuitonValidatorScope.WARNING, errorMap);
235 } else {
236 try {
237 CatchBatch catchBatch =
238 persistenceService.getCatchBatchFromFishingOperation(fishingOperationId);
239
240 checkOperation(fishingOperation, catchBatch, validator);
241 } catch (InvalidBatchModelException e) {
242
243
244 if (log.isDebugEnabled()) {
245 log.debug("Invalid batch model", e);
246 }
247 Map<String, List<String>> errorMap = Maps.newHashMap();
248 errorMap.put("catches", Lists.newArrayList(t("tutti.validator.warning.fishingOperation.invalid.batch.model")));
249 validator.addMessagesForScope(NuitonValidatorScope.WARNING, errorMap);
250 }
251 }
252 }
253
254 protected void transfertValidatorResult(NuitonValidatorResult validatorResult, List<String> errors) {
255 if (validatorResult.hasFatalMessages()) {
256 errors.addAll(validatorResult.getMessagesForScope(NuitonValidatorScope.FATAL));
257 }
258
259 if (validatorResult.hasErrorMessagess()) {
260 errors.addAll(validatorResult.getMessagesForScope(NuitonValidatorScope.ERROR));
261 }
262 }
263
264
265
266
267
268
269
270
271 protected void checkOperation(FishingOperation fishingOperation,
272 CatchBatch catchBatch,
273 NuitonValidatorResult validator) {
274 if (log.isDebugEnabled()) {
275 log.debug("Will check fishingOperation: " + fishingOperation);
276 }
277
278 List<String> errors = Lists.newArrayList();
279 Integer fishingOperationId = fishingOperation.getIdAsInt();
280
281 NuitonValidatorResult fishingOperationValidationResult = validationService.validateValidateFishingOperation(fishingOperation);
282 transfertValidatorResult(fishingOperationValidationResult, errors);
283
284 BatchContainer<SpeciesBatch> rootSpeciesBatch = null;
285 boolean isCatchBatch = persistenceService.isFishingOperationWithCatchBatch(fishingOperationId);
286 boolean error = !isCatchBatch;
287
288 if (isCatchBatch) {
289
290 NuitonValidatorResult catchBatchValidatorResult = validationService.validateValidateCatchBatch(catchBatch);
291 transfertValidatorResult(catchBatchValidatorResult, errors);
292
293 rootSpeciesBatch = persistenceService.getRootSpeciesBatch(fishingOperationId, true);
294
295 if (rootSpeciesBatch != null) {
296 List<SpeciesBatch> roots = rootSpeciesBatch.getChildren();
297
298 for (SpeciesBatch batch : roots) {
299 NuitonValidatorResult speciesValidatorResult = validationService.validateValidateSpeciesBatch(batch);
300 transfertValidatorResult(speciesValidatorResult, errors);
301
302 try {
303 weightComputingService.computeSpeciesBatch(batch);
304
305 } catch (ApplicationBusinessException e) {
306 errors.add(e.getMessage());
307 error = true;
308 }
309 }
310 }
311 }
312 if (error) {
313 rootSpeciesBatch = persistenceService.getRootSpeciesBatch(fishingOperationId, true);
314 }
315
316 BatchContainer<SpeciesBatch> rootBenthosBatch = null;
317 error = false;
318 if (isCatchBatch) {
319 rootBenthosBatch = persistenceService.getRootBenthosBatch(fishingOperationId, true);
320
321 if (rootBenthosBatch != null) {
322 List<SpeciesBatch> roots = rootBenthosBatch.getChildren();
323
324 for (SpeciesBatch batch : roots) {
325
326 NuitonValidatorResult benthosValidatorResult = validationService.validateValidateBenthosBatch(batch);
327 transfertValidatorResult(benthosValidatorResult, errors);
328
329 try {
330 weightComputingService.computeBenthosBatch(batch);
331
332 } catch (ApplicationBusinessException e) {
333 errors.add(e.getMessage());
334 error = true;
335 }
336 }
337 }
338 }
339 if (error) {
340 rootBenthosBatch = persistenceService.getRootBenthosBatch(fishingOperationId, true);
341 }
342 if (isCatchBatch) {
343 List<AccidentalBatch> accidentalBatchs = persistenceService.getAllAccidentalBatch(fishingOperationId);
344 if (accidentalBatchs != null) {
345 for (AccidentalBatch accidentalBatch : accidentalBatchs) {
346 NuitonValidatorResult accidentalBatchValidatorResult = validationService.validateValidateAccidentalBatch(accidentalBatch);
347 transfertValidatorResult(accidentalBatchValidatorResult, errors);
348 }
349 }
350 List<IndividualObservationBatch> individualObservationBatchs = persistenceService.getAllIndividualObservationBatchsForFishingOperation(fishingOperationId);
351 if (individualObservationBatchs != null) {
352 for (IndividualObservationBatch individualObservationBatch : individualObservationBatchs) {
353 NuitonValidatorResult individualObservationBatchValidatorResult = validationService.validateValidateIndividualObservationBatch(individualObservationBatch);
354 transfertValidatorResult(individualObservationBatchValidatorResult, errors);
355 }
356 }
357 }
358
359 BatchContainer<MarineLitterBatch> rootMarineLitterBatch;
360 try {
361 Float weight = catchBatch == null ? null : catchBatch.getMarineLitterTotalWeight();
362 rootMarineLitterBatch = weightComputingService.getComputedMarineLitterBatches(fishingOperationId, weight);
363
364 } catch (ApplicationBusinessException e) {
365 errors.add(e.getMessage());
366 rootMarineLitterBatch = persistenceService.getRootMarineLitterBatch(fishingOperationId);
367 }
368
369 try {
370 if (catchBatch != null) {
371 weightComputingService.computeCatchBatchWeights(catchBatch,
372 rootSpeciesBatch,
373 rootBenthosBatch,
374 rootMarineLitterBatch);
375 }
376 } catch (ApplicationBusinessException e) {
377 errors.add(e.getMessage());
378 }
379
380 if (CollectionUtils.isNotEmpty(errors)) {
381 Map<String, List<String>> errorMap = Maps.newHashMap();
382 errorMap.put("catches", errors);
383 validator.addMessagesForScope(NuitonValidatorScope.ERROR, errorMap);
384 }
385
386 TuttiDataContext dataContext = context.getDataContext();
387 if (dataContext.isProtocolFilled()) {
388
389 Map<String, List<String>> warningMap = Maps.newHashMap();
390
391 Decorator<Species> speciesDecorator = decoratorService.getDecoratorByType(Species.class);
392 if (rootSpeciesBatch != null) {
393 List<String> warnings = new ArrayList<>();
394 for (SpeciesBatch batch : rootSpeciesBatch.getChildren()) {
395 if (isSpeciesBatchInvalid(batch)) {
396 String species = speciesDecorator.toString(batch.getSpecies());
397 String categoryValue = decoratorService.getDecorator(batch.getSampleCategoryValue())
398 .toString(batch.getSampleCategoryValue());
399 warnings.add(t("tutti.validator.warning.species.protocolNotRespected", species, categoryValue));
400 }
401 }
402 if (!warnings.isEmpty()) {
403 warningMap.put("species", warnings);
404 }
405 }
406
407 if (rootBenthosBatch != null) {
408 List<String> warnings = new ArrayList<>();
409 for (SpeciesBatch batch : rootBenthosBatch.getChildren()) {
410 if (isBenthosBatchInvalid(batch)) {
411 String species = speciesDecorator.toString(batch.getSpecies());
412 String categoryValue = decoratorService.getDecorator(batch.getSampleCategoryValue())
413 .toString(batch.getSampleCategoryValue());
414 warnings.add(t("tutti.validator.warning.benthos.protocolNotRespected", species, categoryValue));
415 }
416 }
417 if (!warnings.isEmpty()) {
418 warningMap.put("benthos", warnings);
419 }
420 }
421
422 if (MapUtils.isNotEmpty(warningMap)) {
423 validator.addMessagesForScope(NuitonValidatorScope.WARNING, warningMap);
424 }
425 }
426 }
427
428
429
430
431
432
433
434
435 public boolean isSpeciesBatchValid(SpeciesBatch batch, List<SpeciesBatchFrequency> frequencies) {
436 boolean result = true;
437
438 TuttiProtocol protocol = persistenceService.getProtocol();
439
440 if (protocol != null) {
441 Species species = batch.getSpecies();
442 List<SpeciesProtocol> speciesProtocols = protocol.getSpecies();
443 SpeciesProtocol speciesProtocol = TuttiProtocols.getSpeciesProtocol(species, speciesProtocols);
444
445 if (speciesProtocol != null) {
446 List<Integer> mandatoryCategories = speciesProtocol.getMandatorySampleCategoryId();
447
448 SpeciesBatch browsingBatch = batch;
449 while (browsingBatch.getParentBatch() != null) {
450 mandatoryCategories.remove(browsingBatch.getSampleCategoryId());
451 browsingBatch = browsingBatch.getParentBatch();
452 }
453 result = mandatoryCategories.isEmpty() &&
454 (speciesProtocol.getLengthStepPmfmId() != null
455 || CollectionUtils.isNotEmpty(frequencies)
456 || batch.getNumber() != null);
457 }
458 }
459 return result;
460 }
461
462
463
464
465
466
467
468 protected boolean isSpeciesBatchInvalid(SpeciesBatch batch) {
469 if (batch.isChildBatchsEmpty()) {
470 List<SpeciesBatchFrequency> frequencies =
471 persistenceService.getAllSpeciesBatchFrequency(batch.getIdAsInt());
472 return !isSpeciesBatchValid(batch, frequencies);
473 }
474
475 for (SpeciesBatch child : batch.getChildBatchs()) {
476 boolean invalid = isSpeciesBatchInvalid(child);
477 if (invalid) {
478 return true;
479 }
480 }
481 return false;
482 }
483
484
485
486
487
488
489
490 protected boolean isBenthosBatchInvalid(SpeciesBatch batch) {
491 if (batch.isChildBatchsEmpty()) {
492 List<SpeciesBatchFrequency> frequencies =
493 persistenceService.getAllBenthosBatchFrequency(batch.getIdAsInt());
494 return !isBenthosBatchValid(
495 batch,
496 frequencies);
497 }
498
499 for (SpeciesBatch child : batch.getChildBatchs()) {
500 boolean invalid = isBenthosBatchInvalid(child);
501 if (invalid) {
502 return true;
503 }
504 }
505 return false;
506 }
507
508
509
510
511
512 protected List<String> getExportLines(FishingOperation operation, NuitonValidatorResult validationResult) {
513 List<String> lines = Lists.newArrayList();
514
515 lines.add(t("tutti.validator.export.operation",
516 decoratorService.getDecoratorByType(FishingOperation.class).toString(operation)));
517
518
519 Set<String> messages = new LinkedHashSet<String>(validationResult.getMessagesForScope(NuitonValidatorScope.ERROR));
520 lines.addAll(messages.stream().map(message -> t("tutti.validator.export.message.error", t(message))).collect(Collectors.toList()));
521 messages = new LinkedHashSet<String>(validationResult.getMessagesForScope(NuitonValidatorScope.WARNING));
522 lines.addAll(messages.stream().map(message -> t("tutti.validator.export.message.warning", t(message))).collect(Collectors.toList()));
523
524 return lines;
525 }
526
527
528
529
530
531
532
533
534 public boolean isBenthosBatchValid(SpeciesBatch batch, List<SpeciesBatchFrequency> frequencies) {
535
536 TuttiProtocol protocol = persistenceService.getProtocol();
537
538 boolean result = true;
539
540 if (protocol != null) {
541 Species species = batch.getSpecies();
542 List<SpeciesProtocol> speciesProtocols = protocol.getBenthos();
543 SpeciesProtocol speciesProtocol = TuttiProtocols.getSpeciesProtocol(species, speciesProtocols);
544
545 if (speciesProtocol != null) {
546
547 List<Integer> mandatoryCategories =
548 speciesProtocol.getMandatorySampleCategoryId();
549
550 SpeciesBatch browsingBatch = batch;
551 while (browsingBatch.getParentBatch() != null) {
552 mandatoryCategories.remove(browsingBatch.getSampleCategoryId());
553 browsingBatch = browsingBatch.getParentBatch();
554 }
555 result = mandatoryCategories.isEmpty() &&
556 (speciesProtocol.getLengthStepPmfmId() != null
557 || CollectionUtils.isNotEmpty(frequencies)
558 || batch.getNumber() != null);
559 }
560 }
561 return result;
562 }
563
564 }