1 package fr.ifremer.dali.service.control;
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 import com.google.common.collect.Lists;
27 import com.vividsolutions.jts.geom.Coordinate;
28 import com.vividsolutions.jts.geom.Geometry;
29 import com.vividsolutions.jts.geom.GeometryFactory;
30 import com.vividsolutions.jts.geom.Point;
31 import com.vividsolutions.jts.operation.distance.DistanceOp;
32 import fr.ifremer.dali.config.DaliConfiguration;
33 import fr.ifremer.dali.dao.data.measurement.DaliMeasurementDao;
34 import fr.ifremer.dali.dao.data.samplingoperation.DaliSamplingOperationDao;
35 import fr.ifremer.dali.dao.data.survey.DaliSurveyDao;
36 import fr.ifremer.dali.dao.system.rule.DaliRuleDao;
37 import fr.ifremer.dali.dao.technical.Geometries;
38 import fr.ifremer.dali.dto.DaliBeanFactory;
39 import fr.ifremer.dali.dto.DaliBeans;
40 import fr.ifremer.dali.dto.ErrorDTO;
41 import fr.ifremer.dali.dto.configuration.control.ControlRuleDTO;
42 import fr.ifremer.dali.dto.configuration.control.RulePmfmDTO;
43 import fr.ifremer.dali.dto.data.Coordinate1DAware;
44 import fr.ifremer.dali.dto.data.Coordinate2DAware;
45 import fr.ifremer.dali.dto.data.LocationCoordinateAware;
46 import fr.ifremer.dali.dto.data.PositioningPrecisionAware;
47 import fr.ifremer.dali.dto.data.measurement.MeasurementAware;
48 import fr.ifremer.dali.dto.data.measurement.MeasurementDTO;
49 import fr.ifremer.dali.dto.data.sampling.SamplingOperationDTO;
50 import fr.ifremer.dali.dto.data.survey.SurveyDTO;
51 import fr.ifremer.dali.dto.enums.*;
52 import fr.ifremer.dali.dto.referential.pmfm.PmfmDTO;
53 import fr.ifremer.dali.service.DaliTechnicalException;
54 import fr.ifremer.dali.service.observation.ObservationService;
55 import fr.ifremer.quadrige3.core.ProgressionCoreModel;
56 import fr.ifremer.quadrige3.core.dao.technical.Assert;
57 import fr.ifremer.quadrige3.core.dao.technical.Dates;
58 import fr.ifremer.quadrige3.ui.core.dto.CodeOnly;
59 import fr.ifremer.quadrige3.ui.core.dto.referential.BaseReferentialDTO;
60 import org.apache.commons.collections4.CollectionUtils;
61 import org.apache.commons.lang3.ArrayUtils;
62 import org.apache.commons.lang3.StringUtils;
63 import org.apache.commons.logging.Log;
64 import org.apache.commons.logging.LogFactory;
65 import org.springframework.stereotype.Service;
66
67 import javax.annotation.Resource;
68 import java.math.BigDecimal;
69 import java.time.LocalDate;
70 import java.util.*;
71 import java.util.stream.Collectors;
72
73 import static org.nuiton.i18n.I18n.t;
74
75
76
77
78 @Service("daliControlRuleService")
79 public class ControlRuleServiceImpl implements ControlRuleService {
80
81 private static final Log LOG = LogFactory.getLog(ControlRuleServiceImpl.class);
82
83 @Resource(name = "daliRuleDao")
84 private DaliRuleDao ruleDao;
85 @Resource(name = "daliSurveyDao")
86 private DaliSurveyDao surveyDao;
87 @Resource(name = "daliSamplingOperationDao")
88 private DaliSamplingOperationDao samplingOperationDao;
89 @Resource(name = "daliMeasurementDao")
90 private DaliMeasurementDao measurementDao;
91 @Resource(name = "daliSurveyService")
92 private ObservationService observationService;
93 @Resource
94 protected DaliConfiguration configuration;
95
96
97 private Map<SurveyDTO, List<ControlRuleDTO>> rulesBySurveyMap = new WeakHashMap<>();
98
99
100
101
102 @Override
103 public ControlRuleMessagesBean controlSurveys(Collection<? extends SurveyDTO> surveys,
104 boolean updateControlDateWhenSucceed,
105 boolean resetControlDateWhenFailed, ProgressionCoreModel progressionModel) {
106
107 Date controlDate = new Date(System.currentTimeMillis());
108 ControlRuleMessagesBean messages = new ControlRuleMessagesBean(controlDate);
109
110 List<Integer> validControlledElements = Lists.newArrayList();
111 List<Integer> invalidControlledElements = Lists.newArrayList();
112
113 List<SurveyDTO> surveysToControl = surveys.stream().filter(survey -> !DaliBeans.isSurveyValidated(survey)).collect(Collectors.toList());
114 progressionModel.setTotal(surveysToControl.size());
115
116
117 for (final SurveyDTO surveyToControl : surveysToControl) {
118
119 progressionModel.increments(t("dali.service.common.progression",
120 t("dali.service.control"), progressionModel.getCurrent() + 1, progressionModel.getTotal()));
121
122
123
124 SurveyDTO loadedSurveyToControl = observationService.getSurveyWithoutPmfmFiltering(surveyToControl.getId());
125
126
127
128 boolean succeed = executeControlOnSurvey(loadedSurveyToControl,
129 messages,
130 updateControlDateWhenSucceed,
131 resetControlDateWhenFailed,
132 !updateControlDateWhenSucceed && !resetControlDateWhenFailed);
133
134 if (succeed && updateControlDateWhenSucceed) {
135 validControlledElements.add(surveyToControl.getId());
136
137 surveyToControl.setControlDate(controlDate);
138 } else if (!succeed && resetControlDateWhenFailed) {
139 invalidControlledElements.add(surveyToControl.getId());
140
141 surveyToControl.setControlDate(null);
142 }
143
144
145 surveyToControl.setErrors(loadedSurveyToControl.getErrors());
146 Map<Integer, SamplingOperationDTO> samplingOperationsMap = DaliBeans.mapById(surveyToControl.getSamplingOperations());
147 for (SamplingOperationDTO samplingOperationToControl : loadedSurveyToControl.getSamplingOperations()) {
148 SamplingOperationDTO samplingOperation = samplingOperationsMap.get(samplingOperationToControl.getId());
149 if (samplingOperation != null) {
150 samplingOperation.setErrors(samplingOperationToControl.getErrors());
151 }
152 }
153 }
154
155
156 updateSurveysControlDate(validControlledElements, invalidControlledElements, controlDate);
157
158
159 rulesBySurveyMap.clear();
160
161 return messages;
162 }
163
164
165
166
167 @Override
168 public ControlRuleMessagesBean controlSurvey(SurveyDTO survey,
169 boolean updateControlDateWhenSucceed,
170 boolean resetControlDateWhenFailed) {
171
172
173 if (survey == null || DaliBeans.isSurveyValidated(survey)) {
174 return null;
175 }
176
177 Date controlDate = new Date(System.currentTimeMillis());
178 ControlRuleMessagesBean messages = new ControlRuleMessagesBean(controlDate);
179
180 List<Integer> validControlledElements = Lists.newArrayListWithCapacity(1);
181 List<Integer> invalidControlledElements = Lists.newArrayListWithCapacity(1);
182
183
184 boolean success = executeControlOnSurvey(survey, messages, updateControlDateWhenSucceed, resetControlDateWhenFailed, false);
185
186 if (success && updateControlDateWhenSucceed) {
187 validControlledElements.add(survey.getId());
188
189 survey.setControlDate(controlDate);
190 } else if (!success && resetControlDateWhenFailed) {
191 invalidControlledElements.add(survey.getId());
192
193 survey.setControlDate(null);
194 }
195
196
197 updateSurveysControlDate(validControlledElements, invalidControlledElements, controlDate);
198
199
200 rulesBySurveyMap.clear();
201
202 return messages;
203 }
204
205 @Override
206 public boolean controlUniqueObject(ControlRuleDTO rule, Object objectToControl) {
207
208
209 ControlRuleMessagesBean messages = new ControlRuleMessagesBean(null);
210 ErrorDTO error = DaliBeanFactory.newErrorDTO();
211
212 if (objectToControl instanceof BigDecimal) {
213 validBigDecimal((BigDecimal) objectToControl, rule, messages, error, null);
214 } else if (objectToControl instanceof Double) {
215 validDouble((Double) objectToControl, rule, messages, error);
216 } else if (objectToControl instanceof Integer) {
217 validInteger((Integer) objectToControl, rule, messages, error);
218 } else if (objectToControl instanceof Date) {
219 validDate((Date) objectToControl, rule, messages, error);
220 } else if (objectToControl instanceof String) {
221 validString((String) objectToControl, rule, messages, error);
222 } else if (objectToControl instanceof Collection) {
223 validCollection((Collection) objectToControl, rule, messages, error);
224 } else {
225 validObject(objectToControl, rule, messages, error);
226 }
227
228
229 return !error.isError() && !error.isWarning();
230 }
231
232
233
234
235
236
237
238
239 private List<ControlRuleDTO> getRules(SurveyDTO survey, ControlElementValues... elementControls) {
240 return DaliBeans.filterCollection(getRulesForSurvey(survey),
241 controlRule -> ArrayUtils.contains(elementControls, ControlElementValues.getByCode(controlRule.getControlElement().getCode())));
242 }
243
244
245
246
247
248
249
250 private List<ControlRuleDTO> getRulesForSurvey(SurveyDTO survey) {
251 Assert.notNull(survey);
252 Assert.notNull(survey.getDate());
253 Assert.notNull(survey.getProgram());
254 Assert.notNull(survey.getDepartment());
255
256 return rulesBySurveyMap.computeIfAbsent(survey,
257 rules -> ruleDao.findActiveRules(
258 Dates.convertToDate(survey.getDate(), configuration.getDbTimezone()),
259 survey.getProgram().getCode(),
260 survey.getDepartment().getId()));
261 }
262
263 private boolean executeControlOnSurvey(SurveyDTO survey, ControlRuleMessagesBean messages,
264 boolean updateControlDateWhenSucceed,
265 boolean resetControlDateWhenFailed,
266 boolean skipSurveyMeasurements) {
267
268 boolean isSurveyValid = true;
269 survey.getErrors().clear();
270
271
272 final List<ControlRuleDTO> rules = getRules(survey, ControlElementValues.SURVEY);
273 for (final ControlRuleDTO rule : rules) {
274
275
276 final ControlFeatureSurveyValues enumValue = ControlFeatureSurveyValues.getByCode(rule.getControlFeature().getCode());
277 if (enumValue == null) {
278 throw new DaliTechnicalException(String.format("ControlFeatureSurveyValues with code=%s has not been found", rule.getControlFeature().getCode()));
279 }
280 final ErrorDTO error = newControlError(ControlElementValues.SURVEY);
281
282
283 switch (enumValue) {
284 case CAMPAIGN:
285 validObject(survey.getCampaign(), rule, messages, error, SurveyDTO.PROPERTY_CAMPAIGN);
286 break;
287 case LOCATION:
288 validObject(survey.getLocation(), rule, messages, error, SurveyDTO.PROPERTY_LOCATION);
289 break;
290 case PROGRAM:
291 validObject(survey.getProgram(), rule, messages, error, SurveyDTO.PROPERTY_PROGRAM);
292 break;
293 case VALIDATION_COMMENT:
294 validString(survey.getValidationComment(), rule, messages, error, SurveyDTO.PROPERTY_VALIDATION_COMMENT);
295 break;
296 case QUALIFICATION_COMMENT:
297 validString(survey.getQualificationComment(), rule, messages, error, SurveyDTO.PROPERTY_QUALIFICATION_COMMENT);
298 break;
299 case DATE:
300 validLocalDate(survey.getDate(), rule, messages, error, SurveyDTO.PROPERTY_DATE);
301 break;
302 case CONTROL_DATE:
303 validDate(survey.getControlDate(), rule, messages, error, SurveyDTO.PROPERTY_CONTROL_DATE);
304 break;
305 case UPDATE_DATE:
306 validDate(survey.getUpdateDate(), rule, messages, error, SurveyDTO.PROPERTY_UPDATE_DATE);
307 break;
308 case VALIDATION_DATE:
309 validDate(survey.getValidationDate(), rule, messages, error, SurveyDTO.PROPERTY_VALIDATION_DATE);
310 break;
311 case QUALIFICATION_DATE:
312 validDate(survey.getQualificationDate(), rule, messages, error, SurveyDTO.PROPERTY_QUALIFICATION_DATE);
313 break;
314 case TIME:
315 validInteger(survey.getTime(), rule, messages, error, SurveyDTO.PROPERTY_TIME);
316 break;
317 case COMMENT:
318 validString(survey.getComment(), rule, messages, error, SurveyDTO.PROPERTY_COMMENT);
319 break;
320 case LATITUDE_REAL_SURVEY:
321 validDouble(survey.getCoordinate() == null ? null : survey.getCoordinate().getMinLatitude(), rule, messages, error, Coordinate1DAware.PROPERTY_LATITUDE);
322 break;
323 case LONGITUDE_REAL_SURVEY:
324 validDouble(survey.getCoordinate() == null ? null : survey.getCoordinate().getMinLongitude(), rule, messages, error, Coordinate1DAware.PROPERTY_LONGITUDE);
325 break;
326 case NAME:
327 validString(survey.getName(), rule, messages, error, SurveyDTO.PROPERTY_NAME);
328 break;
329 case DEPARTMENT:
330 validObject(survey.getDepartment(), rule, messages, error, SurveyDTO.PROPERTY_DEPARTMENT);
331 break;
332 case POSITIONING:
333 validObject(survey.getPositioning(), rule, messages, error, SurveyDTO.PROPERTY_POSITIONING);
334 break;
335 case POSITIONING_PRECISION:
336 if (survey.getPositioning() != null) {
337 validString(survey.getPositioning().getPrecision(), rule, messages, error, PositioningPrecisionAware.PROPERTY_POSITIONING_PRECISION);
338 }
339 break;
340 case BOTTOM_DEPTH:
341 validDouble(survey.getBottomDepth(), rule, messages, error, SurveyDTO.PROPERTY_BOTTOM_DEPTH);
342 break;
343 case LATITUDE_MAX_LOCATION:
344 validDouble(survey.getLocation().getCoordinate() == null ? null : survey.getLocation().getCoordinate().getMaxLatitude(), rule, messages, error, LocationCoordinateAware.PROPERTY_LOCATION_MAX_LATITUDE);
345 break;
346 case LATITUDE_MIN_LOCATION:
347 validDouble(survey.getLocation().getCoordinate() == null ? null : survey.getLocation().getCoordinate().getMinLatitude(), rule, messages, error, LocationCoordinateAware.PROPERTY_LOCATION_MIN_LATITUDE);
348 break;
349 case LONGITUDE_MAX_LOCATION:
350 validDouble(survey.getLocation().getCoordinate() == null ? null : survey.getLocation().getCoordinate().getMaxLongitude(), rule, messages, error, LocationCoordinateAware.PROPERTY_LOCATION_MAX_LONGITUDE);
351 break;
352 case LONGITUDE_MIN_LOCATION:
353 validDouble(survey.getLocation().getCoordinate() == null ? null : survey.getLocation().getCoordinate().getMinLongitude(), rule, messages, error, LocationCoordinateAware.PROPERTY_LOCATION_MIN_LONGITUDE);
354 break;
355 case OBSERVERS:
356 validCollection(survey.getObservers(), rule, messages, error, SurveyDTO.PROPERTY_OBSERVERS);
357 break;
358 default:
359 break;
360 }
361 if (error.isError() || error.isWarning()) {
362 survey.addErrors(error);
363 if (error.isError()) {
364 isSurveyValid = false;
365 }
366 }
367
368 }
369
370
371 controlGeometry(survey, messages);
372
373
374 if (!skipSurveyMeasurements && !controlMeasurements(survey,
375 getRules(survey, ControlElementValues.MEASUREMENT, ControlElementValues.TAXON_MEASUREMENT),
376 messages,
377 updateControlDateWhenSucceed,
378 resetControlDateWhenFailed)) {
379 isSurveyValid = false;
380 }
381
382
383 List<Integer> validControlledElements = Lists.newArrayList();
384 List<Integer> invalidControlledElements = Lists.newArrayList();
385 for (final SamplingOperationDTO samplingOperation : survey.getSamplingOperations()) {
386 boolean success = executeControlOnSamplingOperation(survey, samplingOperation, messages, updateControlDateWhenSucceed, resetControlDateWhenFailed);
387 if (success && updateControlDateWhenSucceed) {
388 validControlledElements.add(samplingOperation.getId());
389 samplingOperation.setControlDate(messages.getControlDate());
390 } else if (!success && resetControlDateWhenFailed) {
391 invalidControlledElements.add(samplingOperation.getId());
392 samplingOperation.setControlDate(null);
393 }
394 }
395
396
397 updateSamplingOperationsControlDate(validControlledElements, invalidControlledElements, messages.getControlDate());
398
399 return isSurveyValid && invalidControlledElements.size() == 0;
400 }
401
402 private void controlGeometry(SurveyDTO survey, ControlRuleMessagesBean messages) {
403
404
405 if (Geometries.isValid(survey.getCoordinate())
406 && Geometries.isValid(survey.getLocation().getCoordinate())) {
407
408 Geometry surveyGeometry = Geometries.getGeometry(survey.getCoordinate());
409 Geometry locationGeometry = Geometries.getGeometry(survey.getLocation().getCoordinate().getWkt());
410 ErrorDTO error = newControlError(ControlElementValues.SURVEY);
411 int minDistance = configuration.getControlSurveyLocationMinDistanceInMeter();
412
413
414 if (surveyGeometry.getDimension() > 1) {
415 LOG.warn("Unable to control a survey with an area geometry");
416 return;
417 }
418
419 switch (locationGeometry.getDimension()) {
420 case 0:
421
422 if (surveyGeometry.getDimension() == 0) {
423
424 Double distance = Geometries.getDistanceInMeter(surveyGeometry.getCoordinate(), locationGeometry.getCoordinate());
425 if (distance != null && distance > minDistance) {
426 addGeometryMessage(messages, error, t("dali.service.control.geometry.survey.location.aboveMinimum", minDistance),
427 SurveyDTO.PROPERTY_LOCATION,
428 Coordinate2DAware.PROPERTY_LATITUDE_MIN, Coordinate2DAware.PROPERTY_LONGITUDE_MIN);
429 }
430 } else if (surveyGeometry.getDimension() == 1) {
431
432 Coordinate[] coordinates = DistanceOp.nearestPoints(surveyGeometry, locationGeometry);
433 Double distance = Geometries.getDistanceInMeter(coordinates[0], coordinates[1]);
434 if (distance != null && distance > minDistance) {
435 addGeometryMessage(messages, error, t("dali.service.control.geometry.location.survey.aboveMinimum", minDistance),
436 SurveyDTO.PROPERTY_LOCATION,
437 Coordinate2DAware.PROPERTY_LATITUDE_MIN, Coordinate2DAware.PROPERTY_LONGITUDE_MIN,
438 Coordinate2DAware.PROPERTY_LATITUDE_MAX, Coordinate2DAware.PROPERTY_LONGITUDE_MAX);
439 }
440 }
441 break;
442 case 1:
443
444 if (surveyGeometry.getDimension() == 0) {
445
446 Coordinate[] coordinates = DistanceOp.nearestPoints(surveyGeometry, locationGeometry);
447 Double distance = Geometries.getDistanceInMeter(coordinates[0], coordinates[1]);
448 if (distance != null && distance > minDistance) {
449 addGeometryMessage(messages, error, t("dali.service.control.geometry.survey.location.aboveMinimum", minDistance),
450 SurveyDTO.PROPERTY_LOCATION,
451 Coordinate2DAware.PROPERTY_LATITUDE_MIN, Coordinate2DAware.PROPERTY_LONGITUDE_MIN);
452 }
453 } else if (surveyGeometry.getDimension() == 1) {
454
455 Double distanceFromStart = Geometries.getDistanceInMeter(surveyGeometry.getCoordinates()[0], locationGeometry.getCoordinates()[0]);
456 if (distanceFromStart != null && distanceFromStart > minDistance) {
457 addGeometryMessage(messages, error, t("dali.service.control.geometry.survey.location.start.aboveMinimum", minDistance),
458 SurveyDTO.PROPERTY_LOCATION,
459 Coordinate2DAware.PROPERTY_LATITUDE_MIN, Coordinate2DAware.PROPERTY_LONGITUDE_MIN);
460 }
461 Double distanceFromEnd = Geometries.getDistanceInMeter(surveyGeometry.getCoordinates()[1], locationGeometry.getCoordinates()[1]);
462 if (distanceFromEnd != null && distanceFromEnd > minDistance) {
463 addGeometryMessage(messages, error, t("dali.service.control.geometry.survey.location.end.aboveMinimum", minDistance),
464 SurveyDTO.PROPERTY_LOCATION,
465 Coordinate2DAware.PROPERTY_LATITUDE_MAX, Coordinate2DAware.PROPERTY_LONGITUDE_MAX);
466 }
467 }
468 break;
469 default:
470
471 if (surveyGeometry.getDimension() >= 0) {
472
473 Point point = GeometryFactory.createPointFromInternalCoord(surveyGeometry.getCoordinates()[0], surveyGeometry);
474 if (!locationGeometry.covers(point)) {
475 addGeometryMessage(messages, error, t("dali.service.control.geometry.survey.location.notIncluded"),
476 SurveyDTO.PROPERTY_LOCATION,
477 Coordinate2DAware.PROPERTY_LATITUDE_MIN, Coordinate2DAware.PROPERTY_LONGITUDE_MIN);
478 }
479 }
480 if (surveyGeometry.getDimension() == 1) {
481
482 Point point = GeometryFactory.createPointFromInternalCoord(surveyGeometry.getCoordinates()[1], surveyGeometry);
483 if (!locationGeometry.covers(point)) {
484 addGeometryMessage(messages, error, t("dali.service.control.geometry.survey.location.notIncluded"),
485 SurveyDTO.PROPERTY_LOCATION,
486 Coordinate2DAware.PROPERTY_LATITUDE_MAX, Coordinate2DAware.PROPERTY_LONGITUDE_MAX);
487 }
488 }
489 break;
490 }
491
492 if (error.isWarning() || error.isError()) {
493 survey.addErrors(error);
494 }
495 }
496 }
497
498 private boolean executeControlOnSamplingOperation(SurveyDTO survey, SamplingOperationDTO samplingOperation, ControlRuleMessagesBean messages, boolean updateControlDateWhenSucceed, boolean resetControlDateWhenFailed) {
499
500 boolean isSamplingOperationValid = true;
501
502
503 samplingOperation.getErrors().clear();
504
505
506 final List<ControlRuleDTO> rules = getRules(survey, ControlElementValues.SAMPLING_OPERATION);
507 for (final ControlRuleDTO rule : rules) {
508
509
510 final ControlFeatureSamplingOperationValues enumValue = ControlFeatureSamplingOperationValues.getByCode(rule.getControlFeature().getCode());
511 if (enumValue == null) {
512 throw new DaliTechnicalException(String.format("ControlFeatureSamplingOperationValues with code=%s has not been found", rule.getControlFeature().getCode()));
513 }
514 final ErrorDTO error = newControlError(ControlElementValues.SAMPLING_OPERATION);
515
516
517 switch (enumValue) {
518 case TIME:
519 validInteger(samplingOperation.getTime(), rule, messages, error, SamplingOperationDTO.PROPERTY_TIME);
520 break;
521 case COMMENT:
522 validString(samplingOperation.getComment(), rule, messages, error, SamplingOperationDTO.PROPERTY_COMMENT);
523 break;
524 case DEPTH:
525 validDouble(samplingOperation.getDepth(), rule, messages, error, SamplingOperationDTO.PROPERTY_DEPTH);
526 break;
527 case DEPTH_MAX:
528 validDouble(samplingOperation.getMaxDepth(), rule, messages, error, SamplingOperationDTO.PROPERTY_MAX_DEPTH);
529 break;
530 case DEPTH_MIN:
531 validDouble(samplingOperation.getMinDepth(), rule, messages, error, SamplingOperationDTO.PROPERTY_MIN_DEPTH);
532 break;
533 case LATITUDE_REAL:
534 validDouble(samplingOperation.getCoordinate() == null ? null : samplingOperation.getCoordinate().getMinLatitude(), rule, messages, error, Coordinate1DAware.PROPERTY_LATITUDE);
535 break;
536 case LONGITUDE_REAL:
537 validDouble(samplingOperation.getCoordinate() == null ? null : samplingOperation.getCoordinate().getMinLongitude(), rule, messages, error, Coordinate1DAware.PROPERTY_LONGITUDE);
538 break;
539 case NAME:
540 validString(samplingOperation.getName(), rule, messages, error, SamplingOperationDTO.PROPERTY_NAME);
541 break;
542 case POSITIONING:
543 validObject(samplingOperation.getPositioning(), rule, messages, error, SamplingOperationDTO.PROPERTY_POSITIONING);
544 break;
545 case POSITIONING_PRECISION:
546 if (samplingOperation.getPositioning() != null) {
547 validString(samplingOperation.getPositioning().getPrecision(), rule, messages, error, SamplingOperationDTO.PROPERTY_POSITIONING);
548 }
549 break;
550 case GEAR:
551 validObject(samplingOperation.getSamplingEquipment(), rule, messages, error, SamplingOperationDTO.PROPERTY_SAMPLING_EQUIPMENT);
552 break;
553 case SIZE:
554 validDouble(samplingOperation.getSize(), rule, messages, error, SamplingOperationDTO.PROPERTY_SIZE);
555 break;
556 case SIZE_UNIT:
557 validObject(samplingOperation.getSizeUnit(), rule, messages, error, SamplingOperationDTO.PROPERTY_SIZE_UNIT);
558 break;
559 case DEPARTMENT:
560 validObject(samplingOperation.getSamplingDepartment(), rule, messages, error, SamplingOperationDTO.PROPERTY_SAMPLING_DEPARTMENT);
561 break;
562
563 default:
564 break;
565 }
566
567 if (error.isError() || error.isWarning()) {
568 samplingOperation.addErrors(error);
569 if (error.isError()) {
570 isSamplingOperationValid = false;
571 }
572 }
573
574 }
575
576
577 boolean isMeasurementsValid = controlMeasurements(samplingOperation,
578 getRules(survey, ControlElementValues.MEASUREMENT, ControlElementValues.TAXON_MEASUREMENT),
579 messages,
580 updateControlDateWhenSucceed,
581 resetControlDateWhenFailed);
582
583 return isSamplingOperationValid && isMeasurementsValid;
584 }
585
586 private boolean controlMeasurements(MeasurementAware bean, List<ControlRuleDTO> rules, ControlRuleMessagesBean messages,
587 boolean updateControlDateWhenSucceed, boolean resetControlDateWhenFailed) {
588
589 List<ErrorDTO> errors = Lists.newArrayList();
590
591
592 List<Integer> validMeasurementsElements = Lists.newArrayList();
593 List<Integer> invalidMeasurementsElements = Lists.newArrayList();
594 List<Integer> validTaxonMeasurementsElements = Lists.newArrayList();
595 List<Integer> invalidTaxonMeasurementsElements = Lists.newArrayList();
596
597
598 List<MeasurementDTO> measurementsToControl = Lists.newArrayList();
599 List<MeasurementDTO> individualMeasurementsToControl = Lists.newArrayList();
600 DaliBeans.populateMeasurementsFromPmfms(bean, measurementsToControl, individualMeasurementsToControl);
601
602 if (updateControlDateWhenSucceed) {
603
604 for (MeasurementDTO measurement : measurementsToControl) {
605 if (!DaliBeans.isMeasurementEmpty(measurement)) {
606 validMeasurementsElements.add(measurement.getId());
607 }
608 }
609 for (MeasurementDTO individualMeasurement : individualMeasurementsToControl) {
610 if (!DaliBeans.isMeasurementEmpty(individualMeasurement)) {
611 if (DaliBeans.isTaxonMeasurement(individualMeasurement)) {
612 validTaxonMeasurementsElements.add(individualMeasurement.getId());
613 } else {
614 validMeasurementsElements.add(individualMeasurement.getId());
615 }
616 }
617 }
618 }
619
620 for (final ControlRuleDTO rule : rules) {
621
622
623 for (final MeasurementDTO measurement : measurementsToControl) {
624 if (isPmfmFoundInRule(measurement.getPmfm(), rule)) {
625 ErrorDTO error = executeControlOnMeasurement(measurement, rule, false, messages);
626 if (error.isError() || error.isWarning()) {
627 errors.add(error);
628 }
629 if (error.isError() && resetControlDateWhenFailed) {
630 invalidMeasurementsElements.add(measurement.getId());
631 measurement.setControlDate(null);
632 } else if (!error.isError() && updateControlDateWhenSucceed) {
633 measurement.setControlDate(messages.getControlDate());
634 }
635 }
636 }
637
638
639 for (final MeasurementDTO measurement : individualMeasurementsToControl) {
640 if (isPmfmFoundInRule(measurement.getPmfm(), rule)) {
641 ErrorDTO error;
642 if (DaliBeans.isTaxonMeasurement(measurement)) {
643 error = executeControlOnTaxonMeasurement(measurement, rule, messages);
644 } else {
645 error = executeControlOnMeasurement(measurement, rule, true, messages);
646 }
647 if (error.isError() || error.isWarning()) {
648 errors.add(error);
649 }
650 if (error.isError() && resetControlDateWhenFailed) {
651 if (DaliBeans.isTaxonMeasurement(measurement)) {
652 invalidTaxonMeasurementsElements.add(measurement.getId());
653 } else {
654 invalidMeasurementsElements.add(measurement.getId());
655 }
656 measurement.setControlDate(null);
657 } else if (!error.isError() && updateControlDateWhenSucceed) {
658 measurement.setControlDate(messages.getControlDate());
659 }
660 }
661 }
662 }
663
664
665 validMeasurementsElements.removeAll(invalidMeasurementsElements);
666 validTaxonMeasurementsElements.removeAll(invalidTaxonMeasurementsElements);
667
668 updateMeasurementsControlDate(validMeasurementsElements, invalidMeasurementsElements, messages.getControlDate());
669 updateTaxonMeasurementsControlDate(validTaxonMeasurementsElements, invalidTaxonMeasurementsElements, messages.getControlDate());
670
671
672 bean.getErrors().addAll(errors);
673
674 return invalidMeasurementsElements.size() + invalidTaxonMeasurementsElements.size() == 0;
675 }
676
677
678
679
680
681
682
683 private ErrorDTO executeControlOnMeasurement(
684 MeasurementDTO measurement,
685 ControlRuleDTO rule,
686 boolean isIndividual,
687 ControlRuleMessagesBean messages) {
688
689
690 measurement.getErrors().clear();
691
692
693 final ControlFeatureMeasurementValues enumValue = ControlFeatureMeasurementValues.getByCode(rule.getControlFeature().getCode());
694 if (enumValue == null) {
695 throw new DaliTechnicalException(String.format("ControlFeatureMeasurementValues with code=%s has not been found", rule.getControlFeature().getCode()));
696 }
697 final ErrorDTO error = newControlError(ControlElementValues.MEASUREMENT);
698
699
700 switch (enumValue) {
701 case ANALYST:
702 if (!DaliBeans.isMeasurementEmpty(measurement)) {
703 validObject(measurement.getAnalyst(), rule, messages, error, MeasurementDTO.PROPERTY_ANALYST);
704 }
705 break;
706 case PMFM:
707 validObject(measurement.getPmfm(), rule, messages, error, measurement.getPmfm().getId(), isIndividual ? SurveyDTO.PROPERTY_INDIVIDUAL_PMFMS : SurveyDTO.PROPERTY_PMFMS);
708 break;
709 case NUMERICAL_VALUE:
710 validBigDecimal(measurement.getNumericalValue(), rule, messages, error, measurement.getPmfm().getId(), isIndividual ? SurveyDTO.PROPERTY_INDIVIDUAL_PMFMS : SurveyDTO.PROPERTY_PMFMS);
711 break;
712 case QUALITATIVE_VALUE:
713 validObject(measurement.getQualitativeValue(), rule, messages, error, measurement.getPmfm().getId(), isIndividual ? SurveyDTO.PROPERTY_INDIVIDUAL_PMFMS : SurveyDTO.PROPERTY_PMFMS);
714 break;
715 default:
716 break;
717 }
718
719 if (error.isError() || error.isWarning()) {
720 if (isIndividual) {
721 error.setIndividualId(measurement.getIndividualId());
722 }
723 if (measurement.getErrors() == null) {
724 measurement.setErrors(new ArrayList<>());
725 }
726 measurement.addErrors(error);
727 }
728
729 return error;
730 }
731
732
733
734
735
736
737
738 private ErrorDTO executeControlOnTaxonMeasurement(
739 MeasurementDTO measurement,
740 ControlRuleDTO rule,
741 ControlRuleMessagesBean messages) {
742
743
744 measurement.getErrors().clear();
745
746
747 final ControlFeatureTaxonMeasurementValues enumValue = ControlFeatureTaxonMeasurementValues.getByCode(rule.getControlFeature().getCode());
748 if (enumValue == null) {
749 throw new DaliTechnicalException(String.format("ControlFeatureTaxonMeasurementValues with code=%s has not been found", rule.getControlFeature().getCode()));
750 }
751 final ErrorDTO error = newControlError(ControlElementValues.TAXON_MEASUREMENT);
752
753
754 switch (enumValue) {
755 case ANALYST:
756 if (!DaliBeans.isMeasurementEmpty(measurement)) {
757 validObject(measurement.getAnalyst(), rule, messages, error, MeasurementDTO.PROPERTY_ANALYST);
758 }
759 break;
760 case PMFM:
761 validObject(measurement.getPmfm(), rule, messages, error, measurement.getPmfm().getId(), SurveyDTO.PROPERTY_INDIVIDUAL_PMFMS);
762 break;
763 case NUMERICAL_VALUE:
764 validBigDecimal(measurement.getNumericalValue(), rule, messages, error, measurement.getPmfm().getId(), SurveyDTO.PROPERTY_INDIVIDUAL_PMFMS);
765 break;
766 case QUALITATIVE_VALUE:
767 validObject(measurement.getQualitativeValue(), rule, messages, error, measurement.getPmfm().getId(), SurveyDTO.PROPERTY_INDIVIDUAL_PMFMS);
768 break;
769 case TAXON:
770 validObject(measurement.getTaxon(), rule, messages, error, MeasurementDTO.PROPERTY_TAXON);
771 break;
772 case TAXON_GROUP:
773 validObject(measurement.getTaxonGroup(), rule, messages, error, MeasurementDTO.PROPERTY_TAXON_GROUP);
774 break;
775 default:
776 break;
777 }
778
779 if (error.isError() || error.isWarning()) {
780 error.setIndividualId(measurement.getIndividualId());
781 if (measurement.getErrors() == null) {
782 measurement.setErrors(new ArrayList<>());
783 }
784 measurement.addErrors(error);
785 }
786
787 return error;
788 }
789
790
791
792
793
794
795
796
797
798
799 private void validObject(Object object, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, String... propertyNames) {
800 validObject(object, rule, messages, error, null, propertyNames);
801 }
802
803
804
805
806
807
808
809
810
811
812
813 private void validObject(Object object, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, Integer pmfmId, String... propertyNames) {
814
815 switch (ControlFunctionValues.getFunctionValue(rule.getFunction().getId())) {
816
817 case IS_EMPTY:
818 if (object != null) {
819 addMessage(messages, rule, error, pmfmId, propertyNames);
820 }
821 break;
822
823 case NOT_EMPTY:
824 if (object == null) {
825 addMessage(messages, rule, error, pmfmId, propertyNames);
826 }
827 break;
828
829 case IS_AMONG:
830 if (rule.getAllowedValues() != null) {
831
832 List<String> allowedValues = Lists.newArrayList(rule.getAllowedValues().split(configuration.getValueSeparator()));
833 if (allowedValues.isEmpty()) break;
834
835 if (object instanceof BaseReferentialDTO) {
836 BaseReferentialDTO baseObject = (BaseReferentialDTO) object;
837
838
839 if (StringUtils.isNumeric(allowedValues.get(0))) {
840
841 if (baseObject instanceof CodeOnly) {
842
843
844 if (LOG.isDebugEnabled()) {
845 LOG.debug(String.format("the %s '%s' is not comparable with allowed values %s",
846 baseObject.getClass(), ((CodeOnly) baseObject).getCode(), allowedValues));
847 }
848 addMessage(messages, rule, error, pmfmId, propertyNames);
849
850 } else {
851
852
853 if (!allowedValues.contains(baseObject.getId().toString())) {
854 if (LOG.isDebugEnabled()) {
855 LOG.debug(String.format("the %s '%s' is not in allowed values %s",
856 baseObject.getClass(), baseObject.getId(), allowedValues));
857 }
858 addMessage(messages, rule, error, pmfmId, propertyNames);
859 }
860 }
861
862 } else {
863
864 if (baseObject instanceof CodeOnly) {
865
866
867 CodeOnly codeBaseObject = (CodeOnly) baseObject;
868 if (!allowedValues.contains(codeBaseObject.getCode())) {
869 if (LOG.isDebugEnabled()) {
870 LOG.debug(String.format("the %s '%s' is not in allowed values %s",
871 baseObject.getClass(), codeBaseObject.getCode(), allowedValues));
872 }
873 addMessage(messages, rule, error, pmfmId, propertyNames);
874 }
875
876 } else {
877
878
879 if (!allowedValues.contains(baseObject.getName())) {
880 if (LOG.isDebugEnabled()) {
881 LOG.debug(String.format("the %s '%s' is not in allowed values %s",
882 baseObject.getClass(), baseObject.getName(), allowedValues));
883 }
884 addMessage(messages, rule, error, pmfmId, propertyNames);
885 }
886 }
887 }
888 } else {
889
890 addMessage(messages, rule, error, pmfmId, propertyNames);
891 }
892 }
893 break;
894 default:
895
896 break;
897 }
898 }
899
900 private void validCollection(Collection collection, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, String... propertyNames) {
901
902 switch (ControlFunctionValues.getFunctionValue(rule.getFunction().getId())) {
903
904 case IS_EMPTY:
905 if (CollectionUtils.isNotEmpty(collection)) {
906 addMessage(messages, rule, error, null, propertyNames);
907 }
908 break;
909
910 case NOT_EMPTY:
911 if (CollectionUtils.isEmpty(collection)) {
912 addMessage(messages, rule, error, null, propertyNames);
913 }
914 break;
915
916 case IS_AMONG:
917 if (rule.getAllowedValues() != null) {
918 if (CollectionUtils.isNotEmpty(collection)) {
919
920
921 for (Object object : collection) {
922
923 validObject(object, rule, messages, error, propertyNames);
924
925
926 if (error.isWarning() || error.isError()) break;
927 }
928
929 } else {
930 addMessage(messages, rule, error, null, propertyNames);
931 }
932 }
933 break;
934 default:
935
936 break;
937 }
938
939 }
940
941
942
943
944
945
946
947
948
949
950 private void validDate(Date dateValue, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, String... propertyNames) {
951
952 switch (ControlFunctionValues.getFunctionValue(rule.getFunction().getId())) {
953
954 case IS_EMPTY:
955 if (dateValue != null) {
956 addMessage(messages, rule, error, null, propertyNames);
957 }
958 break;
959
960 case NOT_EMPTY:
961 if (dateValue == null) {
962 addMessage(messages, rule, error, null, propertyNames);
963 }
964 break;
965
966 case MIN_MAX_DATE:
967 if (dateValue == null) {
968 addMessage(messages, rule, error, null, propertyNames);
969 } else {
970
971
972 Date minDate = null;
973 if (rule.getMin() != null) {
974 minDate = (Date) rule.getMin();
975 }
976
977
978 Date maxDate = null;
979 if (rule.getMax() != null) {
980 maxDate = (Date) rule.getMax();
981 }
982
983
984 if (minDate != null && maxDate != null) {
985 if (dateValue.before(minDate) || dateValue.after(maxDate)) {
986 addMessage(messages, rule, error, null, propertyNames);
987 }
988 } else if (minDate != null) {
989 if (dateValue.before(minDate)) {
990 addMessage(messages, rule, error, null, propertyNames);
991 }
992 } else if (maxDate != null) {
993 if (dateValue.after(maxDate)) {
994 addMessage(messages, rule, error, null, propertyNames);
995 }
996 }
997 }
998 break;
999
1000 default:
1001
1002 break;
1003 }
1004
1005 }
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016 private void validLocalDate(LocalDate dateValue, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, String... propertyNames) {
1017
1018 switch (ControlFunctionValues.getFunctionValue(rule.getFunction().getId())) {
1019
1020 case IS_EMPTY:
1021 if (dateValue != null) {
1022 addMessage(messages, rule, error, null, propertyNames);
1023 }
1024 break;
1025
1026 case NOT_EMPTY:
1027 if (dateValue == null) {
1028 addMessage(messages, rule, error, null, propertyNames);
1029 }
1030 break;
1031
1032 case MIN_MAX_DATE:
1033 if (dateValue == null) {
1034 addMessage(messages, rule, error, null, propertyNames);
1035 } else {
1036
1037
1038 LocalDate minDate = null;
1039 if (rule.getMin() != null) {
1040 Object min = rule.getMin();
1041 if (min instanceof Date) {
1042 minDate = Dates.convertToLocalDate((Date) min, configuration.getDbTimezone());
1043 } else if (min instanceof LocalDate) {
1044 minDate = (LocalDate) min;
1045 } else {
1046 throw new DaliTechnicalException(String.format("the min date in rule %s is invalid : %s", rule.getCode(), min));
1047 }
1048 }
1049
1050
1051 LocalDate maxDate = null;
1052 if (rule.getMax() != null) {
1053 Object max = rule.getMax();
1054 if (max instanceof Date) {
1055 maxDate = Dates.convertToLocalDate((Date) max, configuration.getDbTimezone());
1056 } else if (max instanceof LocalDate) {
1057 maxDate = (LocalDate) max;
1058 } else {
1059 throw new DaliTechnicalException(String.format("the max date in rule %s is invalid : %s", rule.getCode(), max));
1060 }
1061 }
1062
1063
1064 if (minDate != null && maxDate != null) {
1065 if (dateValue.isBefore(minDate) || dateValue.isAfter(maxDate)) {
1066 addMessage(messages, rule, error, null, propertyNames);
1067 }
1068 } else if (minDate != null) {
1069 if (dateValue.isBefore(minDate)) {
1070 addMessage(messages, rule, error, null, propertyNames);
1071 }
1072 } else if (maxDate != null) {
1073 if (dateValue.isAfter(maxDate)) {
1074 addMessage(messages, rule, error, null, propertyNames);
1075 }
1076 }
1077 }
1078 break;
1079
1080 default:
1081
1082 break;
1083 }
1084
1085 }
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096 @SuppressWarnings("unused")
1097 private void validInteger(Integer integerValue, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, String... propertyNames) {
1098
1099 switch (ControlFunctionValues.getFunctionValue(rule.getFunction().getId())) {
1100
1101 case IS_EMPTY:
1102 if (integerValue != null) {
1103 addMessage(messages, rule, error, null, propertyNames);
1104 }
1105 break;
1106
1107 case NOT_EMPTY:
1108 if (integerValue == null) {
1109 addMessage(messages, rule, error, null, propertyNames);
1110 }
1111 break;
1112
1113 case MIN_MAX:
1114 if (integerValue == null) {
1115 addMessage(messages, rule, error, null, propertyNames);
1116 } else {
1117
1118
1119 Integer minValue = null;
1120 if (rule.getMin() != null) {
1121 minValue = (Integer) rule.getMin();
1122 }
1123
1124
1125 Integer maxValue = null;
1126 if (rule.getMax() != null) {
1127 maxValue = (Integer) rule.getMax();
1128 }
1129
1130
1131 if (minValue != null && maxValue != null) {
1132 if (integerValue < minValue && integerValue > maxValue) {
1133 addMessage(messages, rule, error, null, propertyNames);
1134 }
1135 }
1136 if (minValue != null) {
1137 if (integerValue < minValue) {
1138 addMessage(messages, rule, error, null, propertyNames);
1139 }
1140 }
1141 if (maxValue != null) {
1142 if (integerValue > maxValue) {
1143 addMessage(messages, rule, error, null, propertyNames);
1144 }
1145 }
1146 }
1147 break;
1148
1149 case IS_AMONG:
1150 if (rule.getAllowedValues() != null) {
1151
1152
1153 final List<Integer> integerValues = new ArrayList<>();
1154
1155
1156 final String[] stringValues = rule.getAllowedValues().split(configuration.getValueSeparator());
1157 for (final String stringValue : stringValues) {
1158 integerValues.add(Integer.parseInt(stringValue));
1159 }
1160
1161
1162 if (!integerValues.contains(integerValue)) {
1163 addMessage(messages, rule, error, null, propertyNames);
1164 }
1165 }
1166 break;
1167
1168 default:
1169
1170 break;
1171 }
1172
1173 }
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184 private void validDouble(Double doubleValue, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, String... propertyNames) {
1185 validDouble(doubleValue, rule, messages, error, null, propertyNames);
1186 }
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198 private void validDouble(Double doubleValue, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, Integer pmfmId, String... propertyNames) {
1199
1200 switch (ControlFunctionValues.getFunctionValue(rule.getFunction().getId())) {
1201
1202 case IS_EMPTY:
1203
1204 if (doubleValue != null) {
1205 addMessage(messages, rule, error, pmfmId, propertyNames);
1206 }
1207 break;
1208
1209 case NOT_EMPTY:
1210
1211 if (doubleValue == null) {
1212 addMessage(messages, rule, error, pmfmId, propertyNames);
1213 }
1214 break;
1215
1216 case MIN_MAX:
1217 if (doubleValue == null) {
1218 addMessage(messages, rule, error, pmfmId, propertyNames);
1219 } else {
1220
1221
1222 Double minValue = null;
1223 if (rule.getMin() != null) {
1224 minValue = (Double) rule.getMin();
1225 }
1226
1227
1228 Double maxValue = null;
1229 if (rule.getMax() != null) {
1230 maxValue = (Double) rule.getMax();
1231 }
1232
1233
1234 if (minValue != null && maxValue != null) {
1235 if (doubleValue < minValue || doubleValue > maxValue) {
1236 addMessage(messages, rule, error, pmfmId, propertyNames);
1237 }
1238 } else if (minValue != null) {
1239 if (doubleValue < minValue) {
1240 addMessage(messages, rule, error, pmfmId, propertyNames);
1241 }
1242 } else if (maxValue != null) {
1243 if (doubleValue > maxValue) {
1244 addMessage(messages, rule, error, pmfmId, propertyNames);
1245 }
1246 }
1247 }
1248 break;
1249
1250 case IS_AMONG:
1251 if (rule.getAllowedValues() != null) {
1252
1253
1254 final List<Double> doubleValues = new ArrayList<>();
1255
1256
1257 final String[] stringValues = rule.getAllowedValues().split(configuration.getValueSeparator());
1258 for (final String stringValue : stringValues) {
1259 try {
1260 doubleValues.add(Double.parseDouble(stringValue));
1261 } catch (NumberFormatException nfe) {
1262 if (LOG.isErrorEnabled()) {
1263 LOG.error(String.format("this value '%s' can't be cast as Double", stringValue));
1264 }
1265 }
1266 }
1267
1268
1269 if (!doubleValues.contains(doubleValue)) {
1270 if (LOG.isDebugEnabled()) {
1271 LOG.debug(String.format("the double value %s is not in allowed values %s", doubleValue, doubleValues));
1272 }
1273
1274 addMessage(messages, rule, error, pmfmId, propertyNames);
1275 }
1276 }
1277 break;
1278
1279 default:
1280
1281 break;
1282 }
1283 }
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295 private void validBigDecimal(BigDecimal bigDecimalValue, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, Integer pmfmId, String... propertyNames) {
1296
1297 Double doubleValue = bigDecimalValue == null ? null : bigDecimalValue.doubleValue();
1298 validDouble(doubleValue, rule, messages, error, pmfmId, propertyNames);
1299 }
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310 private void validString(String stringValue, ControlRuleDTO rule, ControlRuleMessagesBean messages, ErrorDTO error, String... propertyNames) {
1311
1312 switch (ControlFunctionValues.getFunctionValue(rule.getFunction().getId())) {
1313
1314 case IS_EMPTY:
1315
1316 if (StringUtils.isNotBlank(stringValue)) {
1317 addMessage(messages, rule, error, null, propertyNames);
1318 }
1319 break;
1320
1321 case NOT_EMPTY:
1322
1323 if (StringUtils.isBlank(stringValue)) {
1324 addMessage(messages, rule, error, null, propertyNames);
1325 }
1326 break;
1327
1328 case IS_AMONG:
1329 if (rule.getAllowedValues() != null) {
1330
1331 final List<String> stringValues = new ArrayList<>();
1332
1333
1334 final String[] stringTabValues = rule.getAllowedValues().split(configuration.getValueSeparator());
1335 Collections.addAll(stringValues, stringTabValues);
1336
1337
1338 if (!stringValues.contains(stringValue)) {
1339 addMessage(messages, rule, error, null, propertyNames);
1340 }
1341 }
1342 break;
1343
1344 default:
1345
1346 break;
1347 }
1348 }
1349
1350 private void addMessage(ControlRuleMessagesBean messages, ControlRuleDTO rule, ErrorDTO error, Integer pmfmId, String... propertyNames) {
1351 error.setPropertyName(Arrays.asList(propertyNames));
1352 error.setPmfmId(pmfmId);
1353 error.setMessage(getMessage(rule));
1354 if (rule.isBlocking()) {
1355 error.setError(true);
1356 messages.addErrorMessage(error.getMessage());
1357 } else {
1358 error.setWarning(true);
1359 messages.addWarningMessage(error.getMessage());
1360 }
1361 }
1362
1363 private void addGeometryMessage(ControlRuleMessagesBean messages, ErrorDTO error, String message, String... propertyNames) {
1364 error.setPropertyName(Arrays.asList(propertyNames));
1365 error.setWarning(true);
1366 error.setMessage(message);
1367 messages.addWarningMessage(message);
1368 }
1369
1370 private String getMessage(ControlRuleDTO rule) {
1371 if (StringUtils.isNotBlank(rule.getMessage())) {
1372 return rule.getMessage();
1373 }
1374
1375
1376 return t("dali.service.control.invalid.message", rule.getCode());
1377 }
1378
1379 private ErrorDTO newControlError(ControlElementValues controlElementValue) {
1380 ErrorDTO error = DaliBeanFactory.newErrorDTO();
1381 error.setWarning(false);
1382 error.setError(false);
1383 error.setControl(true);
1384 error.setControlElementCode(controlElementValue.getCode());
1385 return error;
1386 }
1387
1388 private boolean isPmfmFoundInRule(PmfmDTO pmfm, ControlRuleDTO rule) {
1389
1390 if (rule.isRulePmfmsEmpty()) {
1391
1392 return true;
1393 }
1394
1395 for (RulePmfmDTO rulePmfm : rule.getRulePmfms()) {
1396
1397
1398 if (rulePmfm.getPmfm().getParameter().equals(pmfm.getParameter())
1399 && (rulePmfm.getPmfm().getMatrix() == null || rulePmfm.getPmfm().getMatrix().equals(pmfm.getMatrix()))
1400 && (rulePmfm.getPmfm().getFraction() == null || rulePmfm.getPmfm().getFraction().equals(pmfm.getFraction()))
1401 && (rulePmfm.getPmfm().getMethod() == null || rulePmfm.getPmfm().getMethod().equals(pmfm.getMethod()))
1402 && (rulePmfm.getPmfm().getUnit() == null || rulePmfm.getPmfm().getUnit().equals(pmfm.getUnit()))
1403 ) {
1404 return true;
1405 }
1406 }
1407
1408 return false;
1409 }
1410
1411 private void updateSurveysControlDate(Collection<Integer> validControlledElementsPks, Collection<Integer> invalidControlledElementsPks, Date controlDate) {
1412
1413 if (CollectionUtils.isNotEmpty(validControlledElementsPks)) {
1414 surveyDao.updateSurveysControlDate(validControlledElementsPks, controlDate);
1415 }
1416
1417 if (CollectionUtils.isNotEmpty(invalidControlledElementsPks)) {
1418 surveyDao.updateSurveysControlDate(invalidControlledElementsPks, null);
1419 }
1420
1421 }
1422
1423 private void updateSamplingOperationsControlDate(Collection<Integer> validControlledElementsPks, Collection<Integer> invalidControlledElementsPks, Date controlDate) {
1424
1425 if (CollectionUtils.isNotEmpty(validControlledElementsPks)) {
1426 samplingOperationDao.updateSamplingOperationsControlDate(validControlledElementsPks, controlDate);
1427 }
1428
1429 if (CollectionUtils.isNotEmpty(invalidControlledElementsPks)) {
1430 samplingOperationDao.updateSamplingOperationsControlDate(invalidControlledElementsPks, null);
1431 }
1432
1433 }
1434
1435 private void updateMeasurementsControlDate(Collection<Integer> validControlledElementsPks, Collection<Integer> invalidControlledElementsPks, Date controlDate) {
1436
1437 if (CollectionUtils.isNotEmpty(validControlledElementsPks)) {
1438 measurementDao.updateMeasurementsControlDate(validControlledElementsPks, controlDate);
1439 }
1440
1441 if (CollectionUtils.isNotEmpty(invalidControlledElementsPks)) {
1442 measurementDao.updateMeasurementsControlDate(invalidControlledElementsPks, null);
1443 }
1444
1445 }
1446
1447 private void updateTaxonMeasurementsControlDate(Collection<Integer> validControlledElementsPks, Collection<Integer> invalidControlledElementsPks, Date controlDate) {
1448
1449 if (CollectionUtils.isNotEmpty(validControlledElementsPks)) {
1450 measurementDao.updateTaxonMeasurementsControlDate(validControlledElementsPks, controlDate);
1451 }
1452
1453 if (CollectionUtils.isNotEmpty(invalidControlledElementsPks)) {
1454 measurementDao.updateTaxonMeasurementsControlDate(invalidControlledElementsPks, null);
1455 }
1456
1457 }
1458
1459 }