1 package fr.ifremer.reefdb.dao.system.rule;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.Lists;
26 import fr.ifremer.quadrige3.core.dao.system.rule.*;
27 import fr.ifremer.quadrige3.core.dao.technical.Assert;
28 import fr.ifremer.quadrige3.core.dao.technical.QuadrigeEnumerationDef;
29 import fr.ifremer.quadrige3.core.dao.technical.hibernate.TemporaryDataHelper;
30 import fr.ifremer.quadrige3.core.exception.QuadrigeTechnicalException;
31 import fr.ifremer.reefdb.config.ReefDbConfiguration;
32 import fr.ifremer.reefdb.dao.technical.Daos;
33 import fr.ifremer.reefdb.dto.FunctionDTO;
34 import fr.ifremer.reefdb.dto.ReefDbBeanFactory;
35 import fr.ifremer.reefdb.dto.ReefDbBeans;
36 import fr.ifremer.reefdb.dto.configuration.control.*;
37 import fr.ifremer.reefdb.dto.enums.*;
38 import org.apache.commons.collections4.CollectionUtils;
39 import org.apache.commons.collections4.ListValuedMap;
40 import org.apache.commons.collections4.MapUtils;
41 import org.apache.commons.collections4.MultiMapUtils;
42 import org.apache.commons.lang3.StringUtils;
43 import org.apache.commons.lang3.mutable.MutableBoolean;
44 import org.apache.commons.lang3.time.DateUtils;
45 import org.apache.commons.logging.Log;
46 import org.apache.commons.logging.LogFactory;
47 import org.hibernate.Query;
48 import org.hibernate.SessionFactory;
49 import org.hibernate.type.DateType;
50 import org.hibernate.type.IntegerType;
51 import org.hibernate.type.StringType;
52 import org.nuiton.i18n.I18n;
53 import org.nuiton.util.DateUtil;
54 import org.springframework.beans.factory.InitializingBean;
55 import org.springframework.beans.factory.annotation.Autowired;
56 import org.springframework.dao.DataRetrievalFailureException;
57 import org.springframework.stereotype.Repository;
58
59 import javax.annotation.Resource;
60 import java.text.ParseException;
61 import java.util.*;
62
63
64
65
66 @Repository("reefDbRuleDao")
67 public class ReefDbRuleDaoImpl extends RuleDaoImpl implements ReefDbRuleDao, InitializingBean {
68
69 private static final Log LOG = LogFactory.getLog(ReefDbRuleDaoImpl.class);
70 public static final String DATE_PATTERN = "yyyy-MM-dd";
71
72 @Resource
73 protected ReefDbConfiguration config;
74
75 @Resource(name = "rulePreconditionDao")
76 private RulePreconditionExtendDao rulePreconditionDao;
77 @Resource(name = "ruleGroupDao")
78 private RuleGroupExtendDao ruleGroupDao;
79 @Resource(name = "reefDbRulePmfmDao")
80 protected ReefDbRulePmfmDao rulePmfmDao;
81 @Resource(name = "ruleParameterDao")
82 protected RuleParameterDao ruleParameterDao;
83
84 private int functionIdMinMax;
85 private int functionIdIn;
86 private int functionIdDateMinMax;
87 private int functionParameterIdMin;
88 private int functionParameterIdMax;
89 private int functionParameterIdIn;
90 private int functionParameterIdDateMin;
91 private int functionParameterIdDateMax;
92
93
94
95
96
97
98 @Autowired
99 public ReefDbRuleDaoImpl(SessionFactory sessionFactory) {
100 super(sessionFactory);
101 }
102
103 @Override
104 public void afterPropertiesSet() {
105 initConstants();
106 }
107
108 private void initConstants() {
109
110 functionIdMinMax = ControlFunctionValues.MIN_MAX.getFunctionId();
111 functionIdDateMinMax = ControlFunctionValues.MIN_MAX_DATE.getFunctionId();
112 functionIdIn = ControlFunctionValues.IS_AMONG.getFunctionId();
113
114
115
116 functionParameterIdMin = FunctionParameterId.MIN.getValue();
117 functionParameterIdMax = FunctionParameterId.MAX.getValue();
118 functionParameterIdIn = FunctionParameterId.IN.getValue();
119 functionParameterIdDateMin = FunctionParameterId.DATE_MIN.getValue();
120 functionParameterIdDateMax = FunctionParameterId.DATE_MAX.getValue();
121 }
122
123 @Override
124 public List<ControlRuleDTO> getControlRulesByRuleListCode(String ruleListCode, boolean onlyActive, MutableBoolean incompatibleRule) {
125 Assert.notBlank(ruleListCode);
126
127 Iterator<Object[]> it = queryIterator("rulesForControlOnlyByRuleListCode",
128 "ruleListCode", StringType.INSTANCE, ruleListCode,
129 "functionIdMinMax", IntegerType.INSTANCE, functionIdMinMax,
130 "functionParameterIdMin", IntegerType.INSTANCE, functionParameterIdMin,
131 "functionParameterIdMax", IntegerType.INSTANCE, functionParameterIdMax,
132 "functionIdDateMinMax", IntegerType.INSTANCE, functionIdDateMinMax,
133 "functionParameterIdDateMin", IntegerType.INSTANCE, functionParameterIdDateMin,
134 "functionParameterIdDateMax", IntegerType.INSTANCE, functionParameterIdDateMax,
135 "functionIdIn", IntegerType.INSTANCE, functionIdIn,
136 "functionParameterIdIn", IntegerType.INSTANCE, functionParameterIdIn,
137 "ruleIsActive", StringType.INSTANCE, onlyActive ? Daos.convertToString(true) : null);
138
139 List<ControlRuleDTO> result = Lists.newArrayList();
140 while (it.hasNext()) {
141 Object[] source = it.next();
142 ControlRuleDTO rule = toRuleDTO(Arrays.asList(source).iterator());
143 if (rule != null) {
144
145 result.add(rule);
146 } else if (incompatibleRule != null) {
147 incompatibleRule.setTrue();
148 }
149 }
150
151 for (ControlRuleDTO rule : result) {
152
153
154 rule.setRulePmfms(rulePmfmDao.getRulePmfmByRuleCode(rule.getCode()));
155 }
156
157 return result;
158
159 }
160
161 @Override
162 public List<ControlRuleDTO> getPreconditionedRulesByRuleListCode(String ruleListCode, boolean onlyActive, MutableBoolean incompatibleRule) {
163
164 List<ControlRuleDTO> result = new ArrayList<>();
165 List<PreconditionRuleDTO> preconditionRules = getPreconditionsByRuleListCode(ruleListCode, onlyActive, incompatibleRule);
166
167
168 ListValuedMap<String, PreconditionRuleDTO> preconditionRulesByName = MultiMapUtils.newListValuedHashMap();
169 for (PreconditionRuleDTO preconditionRule : preconditionRules) {
170 preconditionRulesByName.put(preconditionRule.getName(), preconditionRule);
171 }
172
173
174 for (String name : preconditionRulesByName.keySet()) {
175 ControlRuleDTO preconditionedControlRule = ReefDbBeanFactory.newControlRuleDTO();
176
177 preconditionedControlRule.setCode(name);
178
179 preconditionedControlRule.setControlElement(ControlElementValues.MEASUREMENT.toControlElementDTO());
180
181 preconditionedControlRule.setControlFeature(ControlFeatureMeasurementValues.QUALITATIVE_VALUE.toControlFeatureDTO());
182
183
184 boolean active = true;
185 ControlFunctionValues function = null;
186 Set<String> pmfmPairKeys = new HashSet<>();
187 for (PreconditionRuleDTO preconditionRule: preconditionRulesByName.get(name)) {
188 active &= preconditionRule.isActive();
189
190
191 if (function == null) {
192 function = getFunction(preconditionRule);
193 } else {
194 ControlFunctionValues thisFunction = getFunction(preconditionRule);
195 if (!function.equals(thisFunction)) {
196 if (LOG.isWarnEnabled()) {
197 LOG.warn(String.format("Different precondition functions found (preconditionLb=%s)", preconditionedControlRule.getCode()));
198 }
199 if (incompatibleRule != null) incompatibleRule.setTrue();
200
201 continue;
202 }
203 }
204
205
206 pmfmPairKeys.add(String.format("%s#%s",
207 getRulePmfmKey(preconditionRule.getBaseRule().getRulePmfms(0)),
208 getRulePmfmKey(preconditionRule.getUsedRule().getRulePmfms(0))));
209
210 preconditionRule.setRule(preconditionedControlRule);
211 preconditionedControlRule.addPreconditions(preconditionRule);
212 }
213
214 preconditionedControlRule.setActive(active);
215
216 if (function == null) {
217 if (LOG.isWarnEnabled()) {
218 LOG.warn(String.format("Precondition function not found (preconditionLb=%s)", preconditionedControlRule.getCode()));
219 }
220 if (incompatibleRule != null) incompatibleRule.setTrue();
221
222 continue;
223 }
224 preconditionedControlRule.setFunction(function.toFunctionDTO());
225
226
227 if (pmfmPairKeys.size() > 1) {
228
229 if (LOG.isWarnEnabled()) {
230 LOG.warn(String.format("Only 1 pair of PMFMU is allowed in preconditioned rules (preconditionLb=%s)",
231 preconditionedControlRule.getCode()));
232 }
233 if (incompatibleRule != null) incompatibleRule.setTrue();
234
235 continue;
236 }
237
238 preconditionedControlRule.addRulePmfms(preconditionedControlRule.getPreconditions(0).getBaseRule().getRulePmfms(0));
239 preconditionedControlRule.addRulePmfms(preconditionedControlRule.getPreconditions(0).getUsedRule().getRulePmfms(0));
240
241 result.add(preconditionedControlRule);
242 }
243
244 return result;
245 }
246
247
248
249
250
251
252
253
254
255
256 @Override
257 public List<ControlRuleDTO> getGroupedRulesByRuleListCode(String ruleListCode, boolean onlyActive, MutableBoolean incompatibleRule) {
258
259 List<ControlRuleDTO> result = new ArrayList<>();
260 List<RuleGroupDTO> groups = getGroupsByRuleListCode(ruleListCode, onlyActive, incompatibleRule);
261
262
263 ListValuedMap<String, RuleGroupDTO> groupsByName = MultiMapUtils.newListValuedHashMap();
264 for (RuleGroupDTO group : groups) {
265 groupsByName.put(group.getName(), group);
266 }
267
268
269 for (String name : groupsByName.keySet()) {
270 ControlRuleDTO groupedRule = ReefDbBeanFactory.newControlRuleDTO();
271 groupedRule.setCode(name);
272
273 groupedRule.setControlElement(ControlElementValues.MEASUREMENT.toControlElementDTO());
274
275 groupedRule.setControlFeature(ControlFeatureMeasurementValues.PMFM.toControlFeatureDTO());
276
277 groupedRule.setFunction(ControlFunctionValues.NOT_EMPTY_CONDITIONAL.toFunctionDTO());
278
279 boolean active = true;
280
281 for (RuleGroupDTO group: groupsByName.get(name)) {
282 active &= group.isActive();
283
284 if (!group.isIsOr()) {
285 if (LOG.isWarnEnabled()) {
286 LOG.warn(String.format("a group with AND logical operator found (ruleGroupLb=%s), group ignored", group.getName()));
287 }
288 if (incompatibleRule != null) incompatibleRule.setTrue();
289
290 continue;
291 }
292
293 groupedRule.addGroups(group);
294 }
295
296 groupedRule.setActive(active);
297
298
299 Collection<RulePmfmDTO> rulePmfms = null;
300 if (groupedRule.sizeGroups() == 3) {
301 boolean taxonGroupRuleFound = false;
302 boolean taxonRuleFound = false;
303 boolean pmfmRuleFound = false;
304 for (RuleGroupDTO group : groupedRule.getGroups()) {
305 if (ControlFunctionValues.NOT_EMPTY.equals(group.getRule().getFunction())
306 && ControlElementValues.MEASUREMENT.equals(group.getRule().getControlElement())
307 && ControlFeatureMeasurementValues.TAXON_GROUP.equals(group.getRule().getControlFeature())) {
308 taxonGroupRuleFound = true;
309 }
310 if (ControlFunctionValues.NOT_EMPTY.equals(group.getRule().getFunction())
311 && ControlElementValues.MEASUREMENT.equals(group.getRule().getControlElement())
312 && ControlFeatureMeasurementValues.TAXON.equals(group.getRule().getControlFeature())) {
313 taxonRuleFound = true;
314 }
315 if (ControlFunctionValues.NOT_EMPTY.equals(group.getRule().getFunction())
316 && ControlElementValues.MEASUREMENT.equals(group.getRule().getControlElement())
317 && ControlFeatureMeasurementValues.PMFM.equals(group.getRule().getControlFeature())) {
318 pmfmRuleFound = true;
319 rulePmfms = group.getRule().getRulePmfms();
320 }
321 }
322 if (!taxonGroupRuleFound || !taxonRuleFound || !pmfmRuleFound) {
323 if (LOG.isWarnEnabled()) {
324 LOG.warn(String.format("the 3 rules have not been found : taxon_group=%s taxon=%s pmfmu=%s (ruleGroupLb=%s), group ignored",
325 taxonGroupRuleFound, taxonRuleFound, pmfmRuleFound,
326 groupedRule.getCode()));
327 }
328 if (incompatibleRule != null) incompatibleRule.setTrue();
329 continue;
330 }
331
332 } else {
333 if (LOG.isWarnEnabled()) {
334 LOG.warn(String.format("a group without 3 rules has been found (ruleGroupLb=%s), group ignored", groupedRule.getCode()));
335 }
336 if (incompatibleRule != null) incompatibleRule.setTrue();
337 continue;
338 }
339
340
341 groupedRule.addAllRulePmfms(rulePmfms);
342
343
344 groupedRule.setDescription(groupedRule.getGroups(0).getRule().getDescription());
345 groupedRule.setMessage(groupedRule.getGroups(0).getRule().getMessage());
346
347 result.add(groupedRule);
348 }
349
350 return result;
351 }
352
353
354
355
356 @Override
357 public List<ControlRuleDTO> findActiveControlRules(Date date, String programCode, Integer departmentId) {
358
359 List<ControlRuleDTO> result = Lists.newArrayList();
360 Iterator<String> ruleListCodeIt = getActiveRuleListCodes(date, programCode, departmentId);
361 while (ruleListCodeIt.hasNext()) {
362 String ruleListCode = ruleListCodeIt.next();
363 result.addAll(getControlRulesByRuleListCode(ruleListCode, true , null));
364 }
365
366 return result;
367 }
368
369 @Override
370 public List<ControlRuleDTO> findActivePreconditionedRules(Date date, String programCode, Integer departmentId) {
371
372 return findActivePreconditionedRules(getActiveRuleListCodes(date, programCode, departmentId));
373 }
374
375 @Override
376 public List<ControlRuleDTO> findActiveGroupedRules(Date date, String programCode, Integer departmentId) {
377
378 return findActiveGroupedRules(getActiveRuleListCodes(date, programCode, departmentId));
379 }
380
381 @Override
382 public List<ControlRuleDTO> findActivePreconditionedRules(List<String> programCodes) {
383
384 return findActivePreconditionedRules(getActiveRuleListCodes(programCodes));
385 }
386
387 private List<ControlRuleDTO> findActivePreconditionedRules(Iterator<String> ruleListCodeIt) {
388 List<ControlRuleDTO> result = Lists.newArrayList();
389 while (ruleListCodeIt.hasNext()) {
390 String ruleListCode = ruleListCodeIt.next();
391 result.addAll(getPreconditionedRulesByRuleListCode(ruleListCode, true , null));
392 }
393 return result;
394 }
395
396 private List<ControlRuleDTO> findActiveGroupedRules(Iterator<String> ruleListCodeIt) {
397 List<ControlRuleDTO> result = Lists.newArrayList();
398 while (ruleListCodeIt.hasNext()) {
399 String ruleListCode = ruleListCodeIt.next();
400 result.addAll(getGroupedRulesByRuleListCode(ruleListCode, true , null));
401 }
402 return result;
403 }
404
405
406 @Override
407 public void save(final ControlRuleDTO source, String ruleListCd) {
408 Assert.notNull(source);
409 Assert.notNull(source.getFunction());
410 Assert.notNull(source.getFunction().getId());
411
412
413 RuleList parent = get(RuleListImpl.class, ruleListCd);
414
415 if (source.getFunction().getId() > 0) {
416 save(source, parent);
417 } else if (!source.isPreconditionsEmpty()) {
418 saveWithPreconditions(source, parent);
419 } else if (!source.isGroupsEmpty()) {
420 saveWithGroups(source, parent);
421 }
422 }
423
424 private void save(ControlRuleDTO source, RuleList parent) {
425
426 Assert.isTrue(source.isPreconditionsEmpty());
427 Assert.isTrue(source.isGroupsEmpty());
428
429
430 deleteObsoleteRulePreconditions(source.getCode());
431 deleteObsoleteRuleGroups(source.getCode());
432
433
434 Rule entity = get(source.getCode());
435 boolean isNew = false;
436 if (entity == null) {
437 entity = Rule.Factory.newInstance();
438 entity.setRuleCd(source.getCode());
439 parent.addRules(entity);
440 entity.setRuleList(parent);
441 isNew = true;
442 }
443
444
445 beanToEntity(source, entity);
446
447
448 if (isNew) {
449 getSession().save(entity);
450 } else {
451 getSession().update(entity);
452 }
453
454
455 {
456 Integer functionId = source.getFunction().getId();
457 Map<Integer, RuleParameter> ruleParametersByFunctionParamIds = ReefDbBeans.mapByProperty(entity.getRuleParameters(), "functionParameter.functionParId");
458 final Iterator<Integer> ruleParIdSequence = TemporaryDataHelper.getNewNegativeTemporarySequence(getSession(), RuleParameterImpl.class, true);
459
460
461 if (functionId.equals(functionIdMinMax)) {
462 if (source.getMin() != null && source.getMin() instanceof Double) {
463 updateOrCreateRuleParameter(entity,
464 ruleParIdSequence,
465 ruleParametersByFunctionParamIds,
466 functionParameterIdMin,
467 source.getMin().toString());
468 }
469 if (source.getMax() != null && source.getMax() instanceof Double) {
470 updateOrCreateRuleParameter(entity,
471 ruleParIdSequence,
472 ruleParametersByFunctionParamIds,
473 functionParameterIdMax,
474 source.getMax().toString());
475 }
476 }
477
478
479 else if (functionId.equals(functionIdDateMinMax)) {
480 if (source.getMin() != null && source.getMin() instanceof Date) {
481 updateOrCreateRuleParameter(entity,
482 ruleParIdSequence,
483 ruleParametersByFunctionParamIds,
484 functionParameterIdDateMin,
485 DateUtil.formatDate((Date) source.getMin(), DATE_PATTERN)
486 );
487 }
488 if (source.getMax() != null && source.getMax() instanceof Date) {
489 updateOrCreateRuleParameter(entity,
490 ruleParIdSequence,
491 ruleParametersByFunctionParamIds,
492 functionParameterIdDateMax,
493 DateUtil.formatDate((Date) source.getMax(), DATE_PATTERN)
494 );
495 }
496 }
497
498
499 else if (functionId.equals(functionIdIn) && source.getAllowedValues() != null) {
500 updateOrCreateRuleParameter(entity,
501 ruleParIdSequence,
502 ruleParametersByFunctionParamIds,
503 functionParameterIdIn,
504 source.getAllowedValues());
505 }
506
507
508 if (MapUtils.isNotEmpty(ruleParametersByFunctionParamIds)) {
509 ruleParameterDao.remove(ruleParametersByFunctionParamIds.values());
510 entity.getRuleParameters().removeAll(ruleParametersByFunctionParamIds.values());
511 }
512
513 getSession().update(entity);
514 }
515
516 getSession().flush();
517
518
519 {
520 final Map<Integer, RulePmfm> rulePmfmsToRemove = ReefDbBeans.mapByProperty(entity.getRulePmfms(), "rulePmfmId");
521 if (CollectionUtils.isNotEmpty(source.getRulePmfms())) {
522 source.getRulePmfms().forEach(rulePmfm -> {
523 rulePmfm = rulePmfmDao.save(rulePmfm, source.getCode());
524 rulePmfmsToRemove.remove(rulePmfm.getId());
525 });
526 }
527
528
529 if (MapUtils.isNotEmpty(rulePmfmsToRemove)) {
530 rulePmfmDao.removeByIds(rulePmfmsToRemove.keySet());
531 entity.getRulePmfms().removeAll(rulePmfmsToRemove.values());
532 }
533 }
534
535
536 source.setNewCode(false);
537 }
538
539 private void saveWithPreconditions(ControlRuleDTO source, RuleList parent) {
540
541 Assert.isTrue(!source.isPreconditionsEmpty());
542 Assert.isTrue(source.isGroupsEmpty());
543
544
545 deleteObsoleteRule(source.getCode());
546
547 deleteObsoleteRuleGroups(source.getCode());
548
549 final Iterator<Integer> preconditionIdSequence = TemporaryDataHelper.getNewNegativeTemporarySequence(getSession(), RulePreconditionImpl.class, true);
550
551 for (PreconditionRuleDTO precondition: source.getPreconditions()) {
552
553
554 save(precondition.getBaseRule(), parent);
555 save(precondition.getUsedRule(), parent);
556
557 RulePrecondition entity = precondition.getId() != null ? rulePreconditionDao.get(precondition.getId()) : null;
558 boolean isNew = false;
559 if (entity == null) {
560 entity = RulePrecondition.Factory.newInstance();
561 entity.setRulePrecondId(preconditionIdSequence.next());
562 isNew = true;
563 }
564
565 Rule baseRule = get(precondition.getBaseRule().getCode());
566 Assert.notNull(baseRule);
567 Rule usedRule = get(precondition.getUsedRule().getCode());
568 Assert.notNull(usedRule);
569
570 entity.setRule(baseRule);
571 entity.setUsedRule(usedRule);
572
573 entity.setRulePrecondIsActive(Daos.convertToString(source.isActive()));
574 entity.setRulePrecondIsBidir(Daos.convertToString(precondition.isBidirectional()));
575
576 entity.setRulePrecondLb(source.getCode());
577
578 if (isNew) {
579 getSession().save(entity);
580 precondition.setId(entity.getRulePrecondId());
581 } else {
582 getSession().update(entity);
583 }
584 }
585
586 }
587
588 private void saveWithGroups(ControlRuleDTO source, RuleList parent) {
589
590 Assert.isTrue(!source.isGroupsEmpty());
591 Assert.isTrue(source.isPreconditionsEmpty());
592 final Iterator<Integer> groupIdSequence = TemporaryDataHelper.getNewNegativeTemporarySequence(getSession(), RuleGroupImpl.class, true);
593
594
595 deleteObsoleteRule(source.getCode());
596
597 deleteObsoleteRulePreconditions(source.getCode());
598
599 for (RuleGroupDTO group: source.getGroups()) {
600
601
602 ControlRuleDTO groupedRule = group.getRule();
603
604 groupedRule.setDescription(source.getDescription());
605 groupedRule.setMessage(source.getMessage());
606
607 save(groupedRule, parent);
608
609 RuleGroup entity = group.getId() != null ? ruleGroupDao.get(group.getId()) : null;
610 boolean isNew = false;
611 if (entity == null) {
612 entity = RuleGroup.Factory.newInstance();
613 entity.setRuleGroupId(groupIdSequence.next());
614 isNew = true;
615 }
616
617 Rule rule = get(group.getRule().getCode());
618 Assert.notNull(rule);
619
620 entity.setRule(rule);
621
622 entity.setRuleGroupIsActive(Daos.convertToString(source.isActive()));
623 entity.setRuleGroupIsOr(Daos.convertToString(group.isIsOr()));
624
625 entity.setRuleGroupLb(source.getCode());
626
627 if (isNew) {
628 getSession().save(entity);
629 group.setId(entity.getRuleGroupId());
630 } else {
631 getSession().update(entity);
632 }
633 }
634 }
635
636
637
638
639 @Override
640 public List<FunctionDTO> getAllFunction() {
641
642
643
644 Iterator<Function> it = queryIteratorTyped("allFunctionEntity");
645
646 List<FunctionDTO> result = Lists.newArrayList();
647 while (it.hasNext()) {
648 Function source = it.next();
649 FunctionDTO target = toFunctionDTO(source, true );
650 if (target != null) {
651 result.add(target);
652 }
653 }
654
655 return result;
656 }
657
658 @Override
659 public boolean ruleExists(String ruleCode) {
660 Assert.notBlank(ruleCode);
661
662 return queryUnique("ruleExists", "ruleCode", StringType.INSTANCE, ruleCode) != null;
663 }
664
665
666
667 private void deleteObsoleteRule(String ruleCode) {
668 Rule rule = get(ruleCode);
669 if (rule != null) {
670 remove(rule);
671 }
672 }
673
674 private void deleteObsoleteRulePreconditions(String ruleCode) {
675 List<RulePrecondition> rulePreconditions = rulePreconditionDao.getByCode(ruleCode);
676 if (CollectionUtils.isNotEmpty(rulePreconditions)) {
677 rulePreconditionDao.remove(rulePreconditions);
678 }
679 }
680
681 private void deleteObsoleteRuleGroups(String ruleCode) {
682 List<RuleGroup> ruleGroups = ruleGroupDao.getByCode(ruleCode);
683 if (CollectionUtils.isNotEmpty(ruleGroups)) {
684 ruleGroupDao.remove(ruleGroups);
685 }
686 }
687
688 private Iterator<String> getActiveRuleListCodes(Date date, String programCode, Integer departmentId) {
689
690
691 return queryIteratorTyped("activeRuleListCodesByCriteria",
692 "programCode", StringType.INSTANCE, programCode,
693 "departmentId", IntegerType.INSTANCE, departmentId,
694 "date", DateType.INSTANCE, date);
695
696 }
697
698 @SuppressWarnings("unchecked")
699 private Iterator<String> getActiveRuleListCodes(List<String> programCodes) {
700
701
702 Query query = createQuery("activeRuleListCodesByProgramCodes").setParameterList("programCodes", programCodes);
703 return query.iterate();
704
705 }
706
707 private ControlRuleDTO getRule(String ruleCode) {
708
709 Object[] row = queryUnique("ruleByCode",
710 "ruleCode", StringType.INSTANCE, ruleCode,
711 "functionIdMinMax", IntegerType.INSTANCE, functionIdMinMax,
712 "functionParameterIdMin", IntegerType.INSTANCE, functionParameterIdMin,
713 "functionParameterIdMax", IntegerType.INSTANCE, functionParameterIdMax,
714 "functionIdDateMinMax", IntegerType.INSTANCE, functionIdDateMinMax,
715 "functionParameterIdDateMin", IntegerType.INSTANCE, functionParameterIdDateMin,
716 "functionParameterIdDateMax", IntegerType.INSTANCE, functionParameterIdDateMax,
717 "functionIdIn", IntegerType.INSTANCE, functionIdIn,
718 "functionParameterIdIn", IntegerType.INSTANCE, functionParameterIdIn);
719
720 if (row == null)
721 throw new DataRetrievalFailureException("can't load rule with code = " + ruleCode);
722
723
724 ControlRuleDTO controlRule = toRuleDTO(Arrays.asList(row).iterator());
725 if (controlRule != null) {
726 controlRule.setRulePmfms(rulePmfmDao.getRulePmfmByRuleCode(controlRule.getCode()));
727 }
728 return controlRule;
729 }
730
731 private List<PreconditionRuleDTO> getPreconditionsByRuleListCode(String ruleListCode, boolean onlyActive, MutableBoolean incompatibleRule) {
732
733 Iterator<Object[]> rows = queryIterator("rulePreconditionsByRuleListCode",
734 "ruleListCode", StringType.INSTANCE, ruleListCode,
735 "rulePreconditionIsActive", StringType.INSTANCE, onlyActive ? Daos.convertToString(true) : null);
736
737 List<PreconditionRuleDTO> result = new ArrayList<>();
738 while (rows.hasNext()) {
739 Object[] row = rows.next();
740 PreconditionRuleDTO preconditionRule = toPreconditionRuleDTO(Arrays.asList(row).iterator());
741 if (preconditionRule != null) {
742
743 result.add(preconditionRule);
744 } else if (incompatibleRule != null) {
745 incompatibleRule.setTrue();
746 }
747 }
748 return result;
749 }
750
751 private PreconditionRuleDTO toPreconditionRuleDTO(Iterator<Object> source) {
752 PreconditionRuleDTO result = ReefDbBeanFactory.newPreconditionRuleDTO();
753 result.setId((Integer) source.next());
754 result.setName((String) source.next());
755 result.setActive(Daos.safeConvertToBoolean(source.next()));
756 result.setBidirectional(Daos.safeConvertToBoolean(source.next()));
757
758
759 ControlRuleDTO baseRule = getRule((String) source.next());
760 ControlRuleDTO usedRule = getRule((String) source.next());
761
762
763 if (baseRule == null || usedRule == null) return null;
764
765 for (ControlRuleDTO rule : ImmutableList.of(baseRule, usedRule)) {
766
767 if (
768 (!ControlElementValues.MEASUREMENT.equals(rule.getControlElement()))
769 ||
770 (!ControlFeatureMeasurementValues.QUALITATIVE_VALUE.equals(rule.getControlFeature())
771 && !ControlFeatureMeasurementValues.NUMERICAL_VALUE.equals(rule.getControlFeature())
772 )) {
773 if (LOG.isWarnEnabled()) {
774 LOG.warn(String.format("Only measurement's qualitative or numerical value are allowed in preconditioned rule (precondition=%s, rule=%s)",
775 result.getId(), rule.getCode()));
776 }
777 return null;
778 }
779
780
781 if (rule.sizeRulePmfms() != 1) {
782 if (LOG.isWarnEnabled()) {
783 LOG.warn(String.format("Only 1 PMFMU is allowed in preconditioned rule (precondition=%s, rule=%s)",
784 result.getId(), rule.getCode()));
785 }
786 return null;
787 }
788 }
789
790
791 result.setBaseRule(baseRule);
792 result.setUsedRule(usedRule);
793 return result;
794 }
795
796 private List<RuleGroupDTO> getGroupsByRuleListCode(String ruleListCode, boolean onlyActive, MutableBoolean incompatibleRule) {
797
798 Iterator<Object[]> rows = queryIterator("ruleGroupsByRuleListCode",
799 "ruleListCode", StringType.INSTANCE, ruleListCode,
800 "ruleGroupIsActive", StringType.INSTANCE, onlyActive ? Daos.convertToString(true) : null);
801
802 List<RuleGroupDTO> result = new ArrayList<>();
803 while (rows.hasNext()) {
804 Object[] row = rows.next();
805 RuleGroupDTO ruleGroup = toRuleGroupDTO(Arrays.asList(row).iterator());
806 if (ruleGroup != null) {
807
808 result.add(ruleGroup);
809 } else if (incompatibleRule != null) {
810 incompatibleRule.setTrue();
811 }
812 }
813 return result;
814 }
815
816 private RuleGroupDTO toRuleGroupDTO(Iterator<Object> source) {
817 RuleGroupDTO result = ReefDbBeanFactory.newRuleGroupDTO();
818 result.setId((Integer) source.next());
819 result.setName((String) source.next());
820 result.setActive(Daos.safeConvertToBoolean(source.next()));
821 result.setIsOr(Daos.safeConvertToBoolean(source.next()));
822
823
824 ControlRuleDTO rule = getRule((String) source.next());
825
826
827 if (rule == null) return null;
828 result.setRule(rule);
829
830 return result;
831 }
832
833 private ControlRuleDTO toRuleDTO(Iterator<Object> source) {
834 ControlRuleDTO result = ReefDbBeanFactory.newControlRuleDTO();
835 result.setCode((String) source.next());
836
837 String controlledElementString = (String) source.next();
838
839 if (controlledElementString != null) {
840 int separatorIndex = controlledElementString.lastIndexOf(config.getAttributeSeparator());
841
842 if (separatorIndex == -1 || separatorIndex == controlledElementString.length() - 1) {
843 if (LOG.isWarnEnabled()) {
844 LOG.warn(I18n.t("reefdb.error.dao.ruleList.parse.controlledAttribute", controlledElementString, result.getCode()));
845 }
846 return null;
847 } else {
848 String controlElementCode = controlledElementString.substring(0, separatorIndex);
849 String controlFeatureCode = controlledElementString.substring(separatorIndex + 1);
850
851
852 ControlElementValues controlElementValue = ControlElementValues.getByCode(controlElementCode);
853 if (controlElementValue != null) {
854 result.setControlElement(controlElementValue.toControlElementDTO());
855
856 ControlFeatureDTO controlFeature = null;
857
858 switch (controlElementValue) {
859
860 case MEASUREMENT:
861 controlFeature = ControlFeatureMeasurementValues.toControlFeatureDTO(controlFeatureCode);
862 break;
863 case SAMPLING_OPERATION:
864 controlFeature = ControlFeatureSamplingOperationValues.toControlFeatureDTO(controlFeatureCode);
865 break;
866 case SURVEY:
867 controlFeature = ControlFeatureSurveyValues.toControlFeatureDTO(controlFeatureCode);
868 break;
869 }
870
871 if (controlFeature != null) {
872 result.setControlFeature(controlFeature);
873 } else {
874 if (LOG.isWarnEnabled()) {
875 LOG.warn(I18n.t("reefdb.error.dao.ruleList.rule.skip", result.getCode(), controlledElementString));
876 }
877 return null;
878 }
879 } else {
880 if (LOG.isWarnEnabled()) {
881 LOG.warn(I18n.t("reefdb.error.dao.ruleList.rule.skip", result.getCode(), controlElementCode));
882 }
883 return null;
884 }
885 }
886 }
887
888 result.setDescription((String) source.next());
889 result.setActive(Daos.safeConvertToBoolean(source.next()));
890 result.setBlocking(Daos.safeConvertToBoolean(source.next()));
891 result.setMessage((String) source.next());
892
893
894 Function function = (Function) source.next();
895 result.setFunction(toFunctionDTO(function, false));
896
897
898 String valueMin = (String) source.next();
899 String valueMax = (String) source.next();
900 String dateMin = (String) source.next();
901 String dateMax = (String) source.next();
902 if (result.getFunction().getId().equals(functionIdDateMinMax)) {
903 try {
904 result.setMin(dateMin == null ? null : parseDate(dateMin));
905 } catch (ParseException e) {
906 LOG.warn(String.format("Error when parsing %s as date", dateMin), e);
907 return null;
908 }
909 try {
910 result.setMax(dateMax == null ? null : parseDate(dateMax));
911 } catch (ParseException e) {
912 LOG.warn(String.format("Error when parsing %s as date", dateMax), e);
913 return null;
914 }
915 } else {
916 result.setMin(valueMin == null ? null : Double.parseDouble(valueMin));
917 result.setMax(valueMax == null ? null : Double.parseDouble(valueMax));
918 }
919 result.setAllowedValues((String) source.next());
920
921 return result;
922 }
923
924 private Date parseDate(String s) throws ParseException {
925 return StringUtils.isNumeric(s) ? new Date(Long.parseLong(s)) : DateUtils.parseDate(s, DATE_PATTERN);
926 }
927
928 private FunctionDTO toFunctionDTO(Function function, boolean couldBeNull) {
929 FunctionDTO result = ReefDbBeanFactory.newFunctionDTO();
930 result.setId(function.getFunctionId());
931 ControlFunctionValues functionControlValue = ControlFunctionValues.getFunctionValue(function.getFunctionId());
932 if (functionControlValue == null) {
933 String errorMessage = String.format("Could not found enumeration for Function with id [%s]. Make sure enumeration file has a property like '%s functionId.(...)=%s'",
934 function.getFunctionId(),
935 QuadrigeEnumerationDef.CONFIG_OPTION_PREFIX,
936 function.getFunctionId());
937 if (!couldBeNull) {
938 throw new QuadrigeTechnicalException(errorMessage);
939 }
940
941 LOG.warn(errorMessage);
942 return null;
943 }
944
945 result.setName(functionControlValue.getLabel());
946 return result;
947 }
948
949 private String getRulePmfmKey(RulePmfmDTO rulePmfm) {
950
951 return String.format("%s|%s|%s|%s|%s",
952 rulePmfm.getPmfm().getParameter().getCode(),
953 rulePmfm.getPmfm().getMatrix() != null ? rulePmfm.getPmfm().getMatrix().getId() : "null",
954 rulePmfm.getPmfm().getFraction() != null ? rulePmfm.getPmfm().getFraction().getId() : "null",
955 rulePmfm.getPmfm().getMethod() != null ? rulePmfm.getPmfm().getMethod().getId() : "null",
956 rulePmfm.getPmfm().getUnit() != null ? rulePmfm.getPmfm().getUnit().getId() : "null"
957 );
958 }
959
960 private void beanToEntity(ControlRuleDTO source, Rule target) {
961
962 target.setRuleDc(source.getDescription());
963 String controlledAttribute = source.getControlElement().getCode()
964 .concat(config.getAttributeSeparator())
965 .concat(source.getControlFeature().getCode());
966 target.setRuleControledAttribut(controlledAttribute);
967 target.setRuleErrorMsg(source.getMessage());
968 target.setRuleIsActive(Daos.convertToString(source.isActive()));
969 target.setRuleIsBlocking(Daos.convertToString(source.isBlocking()));
970
971
972 Function function;
973 if (source.getFunction() != null) {
974 function = load(FunctionImpl.class, source.getFunction().getId());
975 } else {
976 throw new DataRetrievalFailureException("ControlRuleDTO object has no Function");
977 }
978 if (function == null) {
979 throw new DataRetrievalFailureException(String.format("function not found with id=%s", source.getFunction().getId()));
980 }
981 target.setFunction(function);
982 }
983
984 private void updateOrCreateRuleParameter(Rule parent,
985 Iterator<Integer> ruleParIdSequence,
986 Map<Integer, RuleParameter> ruleParametersByFunctionParamIds,
987 int functionParameterId,
988 String ruleParameterValue) {
989 RuleParameter rp = ruleParametersByFunctionParamIds.remove(functionParameterId);
990 boolean isNew = false;
991 if (rp == null) {
992 rp = RuleParameterImpl.Factory.newInstance();
993 rp.setFunctionParameter(load(FunctionParameterImpl.class, functionParameterId));
994 rp.setRuleParId(ruleParIdSequence.next());
995 parent.addRuleParameters(rp);
996 rp.setRule(parent);
997 isNew = true;
998 }
999
1000
1001 rp.setRuleParValue(ruleParameterValue);
1002
1003
1004 if (isNew) {
1005 getSession().save(rp);
1006 } else {
1007 getSession().update(rp);
1008 }
1009
1010 }
1011
1012 private ControlFunctionValues getFunction(PreconditionRuleDTO preconditionRule) {
1013 if (ControlFunctionValues.IS_AMONG.equals(preconditionRule.getBaseRule().getFunction())
1014 && ControlFunctionValues.IS_AMONG.equals(preconditionRule.getUsedRule().getFunction())) {
1015 return ControlFunctionValues.PRECONDITION_QUALITATIVE;
1016 } else if (
1017 (ControlFunctionValues.IS_AMONG.equals(preconditionRule.getBaseRule().getFunction())
1018 && ControlFunctionValues.MIN_MAX.equals(preconditionRule.getUsedRule().getFunction()))
1019 ||
1020 (ControlFunctionValues.MIN_MAX.equals(preconditionRule.getBaseRule().getFunction())
1021 && ControlFunctionValues.IS_AMONG.equals(preconditionRule.getUsedRule().getFunction()))) {
1022 return ControlFunctionValues.PRECONDITION_NUMERICAL;
1023 }
1024 return null;
1025 }
1026 }