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
25
26 import com.google.common.collect.Lists;
27 import com.google.common.collect.Sets;
28 import fr.ifremer.quadrige3.core.dao.administration.program.ProgramImpl;
29 import fr.ifremer.quadrige3.core.dao.administration.user.DepartmentImpl;
30 import fr.ifremer.quadrige3.core.dao.administration.user.Quser;
31 import fr.ifremer.quadrige3.core.dao.administration.user.QuserImpl;
32 import fr.ifremer.quadrige3.core.dao.referential.StatusImpl;
33 import fr.ifremer.quadrige3.core.dao.system.rule.RuleList;
34 import fr.ifremer.quadrige3.core.dao.system.rule.RuleListDaoImpl;
35 import fr.ifremer.quadrige3.core.dao.technical.Assert;
36 import fr.ifremer.quadrige3.core.dao.technical.Beans;
37 import fr.ifremer.quadrige3.core.dao.technical.Dates;
38 import fr.ifremer.quadrige3.core.security.SecurityContextHelper;
39 import fr.ifremer.reefdb.config.ReefDbConfiguration;
40 import fr.ifremer.reefdb.dao.administration.user.ReefDbDepartmentDao;
41 import fr.ifremer.reefdb.dao.technical.Daos;
42 import fr.ifremer.reefdb.dto.ReefDbBeanFactory;
43 import fr.ifremer.reefdb.dto.ReefDbBeans;
44 import fr.ifremer.reefdb.dto.configuration.control.PreconditionRuleDTO;
45 import fr.ifremer.reefdb.dto.configuration.control.RuleGroupDTO;
46 import fr.ifremer.reefdb.dto.configuration.control.RuleListDTO;
47 import fr.ifremer.reefdb.dto.referential.DepartmentDTO;
48 import fr.ifremer.reefdb.service.administration.program.ProgramStrategyService;
49 import fr.ifremer.reefdb.service.system.SystemService;
50 import org.apache.commons.collections4.CollectionUtils;
51 import org.apache.commons.lang3.mutable.MutableBoolean;
52 import org.apache.commons.logging.Log;
53 import org.apache.commons.logging.LogFactory;
54 import org.hibernate.SessionFactory;
55 import org.hibernate.type.StringType;
56 import org.springframework.beans.factory.annotation.Autowired;
57 import org.springframework.dao.DataRetrievalFailureException;
58 import org.springframework.stereotype.Repository;
59
60 import javax.annotation.Resource;
61 import java.time.LocalDate;
62 import java.util.*;
63
64 import static org.nuiton.i18n.I18n.t;
65
66
67
68
69
70
71 @Repository("reefDbRuleListDao")
72 public class ReefDbRuleListDaoImpl extends RuleListDaoImpl implements ReefDbRuleListDao {
73
74 private static final Log LOG = LogFactory.getLog(ReefDbRuleListDaoImpl.class);
75
76 @Resource
77 protected ReefDbConfiguration config;
78 @Resource(name = "reefDbRuleDao")
79 protected ReefDbRuleDao ruleDao;
80 @Resource(name = "reefdbProgramStrategyService")
81 protected ProgramStrategyService programStrategyService;
82 @Resource(name = "reefDbDepartmentDao")
83 protected ReefDbDepartmentDao departmentDao;
84
85 @Resource(name = "reefdbSystemService")
86 protected SystemService systemService;
87
88
89
90
91
92 @Autowired
93 public ReefDbRuleListDaoImpl(SessionFactory sessionFactory) {
94 super(sessionFactory);
95 }
96
97
98
99
100 @Override
101 public List<RuleListDTO> getRuleLists() {
102
103 Iterator<Object[]> it = queryIterator("allRuleList");
104
105 return toRuleListDTOs(it);
106 }
107
108 @Override
109 public List<RuleListDTO> getRuleListsForProgram(String programCode) {
110
111 Iterator<Object[]> it = queryIterator("allRuleListWithProgramCode",
112 "programCode", StringType.INSTANCE, programCode);
113
114 return toRuleListDTOs(it);
115 }
116
117
118
119
120 @Override
121 public RuleListDTO getRuleList(String ruleListCode) {
122 Assert.notBlank(ruleListCode);
123
124 Object[] source = queryUnique("ruleListByCode", "ruleListCode", StringType.INSTANCE, ruleListCode);
125
126 if (source == null) {
127 throw new DataRetrievalFailureException("can't load rule list with code = " + ruleListCode);
128 }
129
130 RuleListDTO ruleList = toRuleListDTO(Arrays.asList(source).iterator(), config.getDbTimezone());
131
132 if (fillAndValidRuleList(ruleList,
133 programStrategyService.getManagedProgramCodesByQuserId(SecurityContextHelper.getQuadrigeUserId()),
134 programStrategyService.getWritableProgramCodesByQuserId(SecurityContextHelper.getQuadrigeUserId())))
135
136 return ruleList;
137
138 return null;
139 }
140
141 @Override
142 public boolean ruleListExists(String ruleListCode) {
143 Assert.notBlank(ruleListCode);
144
145 return queryUnique("ruleListByCode", "ruleListCode", StringType.INSTANCE, ruleListCode) != null;
146 }
147
148
149
150
151 @Override
152 public void saveRuleList(RuleListDTO source, Integer quserId) {
153 Assert.notNull(source);
154 Assert.notBlank(source.getCode());
155 Assert.notNull(source.getStatus());
156 Assert.notNull(quserId);
157
158 RuleList target = get(source.getCode());
159 boolean isNew = false;
160 if (target == null) {
161 target = RuleList.Factory.newInstance();
162 target.setRuleListCd(source.getCode());
163
164 target.setStatus(load(StatusImpl.class, source.getStatus().getCode()));
165 isNew = true;
166 }
167
168
169 beanToEntity(source, target, quserId, config.getDbTimezone());
170
171
172 if (isNew) {
173 getSession().save(target);
174 } else {
175 getSession().update(target);
176 }
177
178
179 final List<String> rulesCdsToRemove = ReefDbBeans.collectProperties(target.getRules(), "ruleCd");
180
181
182 if (CollectionUtils.isNotEmpty(source.getControlRules())) {
183 source.getControlRules().forEach(controlRule -> {
184 ruleDao.save(controlRule, source.getCode());
185 rulesCdsToRemove.remove(controlRule.getCode());
186 if (!controlRule.isPreconditionsEmpty()) {
187 for (PreconditionRuleDTO preconditionRule : controlRule.getPreconditions()) {
188 rulesCdsToRemove.remove(preconditionRule.getBaseRule().getCode());
189 rulesCdsToRemove.remove(preconditionRule.getUsedRule().getCode());
190 }
191 }
192 if (!controlRule.isGroupsEmpty()) {
193 for (RuleGroupDTO groupedRule : controlRule.getGroups()) {
194 rulesCdsToRemove.remove(groupedRule.getRule().getCode());
195 }
196 }
197 });
198 }
199
200 getSession().flush();
201 getSession().clear();
202
203
204 if (CollectionUtils.isNotEmpty(rulesCdsToRemove)) {
205 ruleDao.removeByCds(Beans.asStringArray(rulesCdsToRemove));
206
207 getSession().flush();
208 getSession().clear();
209 }
210 }
211
212
213
214 private boolean fillAndValidRuleList(RuleListDTO ruleList, Set<String> managedProgramCodes, Set<String> writableProgramCodes) {
215
216
217 List<String> programCodes = getProgramCodesByRuleListCode(ruleList.getCode());
218
219 if (CollectionUtils.isEmpty(programCodes)) {
220
221 return false;
222 }
223
224
225 boolean canRead = programCodes.stream().anyMatch(writableProgramCodes::contains) || ReefDbBeans.isLocalStatus(ruleList.getStatus());
226 if (!canRead) {
227 if (LOG.isWarnEnabled()) {
228 LOG.warn(t("reefdb.error.dao.ruleList.program.empty", ruleList.getCode()));
229 }
230
231 return false;
232 }
233
234
235 boolean canWrite = managedProgramCodes.containsAll(programCodes) || ReefDbBeans.isLocalStatus(ruleList.getStatus());
236 ruleList.setReadOnly(!canWrite);
237
238
239 ruleList.setPrograms(programStrategyService.getProgramsByCodes(programCodes));
240
241
242 ruleList.setDepartments(getControlledDepartmentsByRuleListCode(ruleList.getCode()));
243
244 MutableBoolean incompatibleRule = new MutableBoolean(false);
245
246
247 ruleList.addAllControlRules(ruleDao.getControlRulesByRuleListCode(ruleList.getCode(), false , incompatibleRule));
248
249 ruleList.addAllControlRules(ruleDao.getPreconditionedRulesByRuleListCode(ruleList.getCode(), false, incompatibleRule));
250
251 ruleList.addAllControlRules(ruleDao.getGroupedRulesByRuleListCode(ruleList.getCode(), false, incompatibleRule));
252
253
254 if (ruleList.isControlRulesEmpty()) {
255 if (LOG.isWarnEnabled()) {
256 LOG.warn(t("reefdb.error.dao.ruleList.rule.empty", ruleList.getCode()));
257 }
258
259 return false;
260 }
261
262 if (incompatibleRule.booleanValue()) ruleList.setReadOnly(true);
263
264 return true;
265 }
266
267 private List<String> getProgramCodesByRuleListCode(String ruleListCode) {
268
269 Assert.notBlank(ruleListCode);
270
271 return queryListTyped("programCodesByRuleListCode",
272 "ruleListCode", StringType.INSTANCE, ruleListCode);
273 }
274
275
276
277
278
279
280
281 private List<DepartmentDTO> getControlledDepartmentsByRuleListCode(String ruleListCode) {
282 Assert.notBlank(ruleListCode);
283
284 List<Integer> depIds = queryListTyped("departmentIdsByRuleListCode",
285 "ruleListCode", StringType.INSTANCE, ruleListCode);
286
287 List<DepartmentDTO> result = Lists.newArrayList();
288 if (CollectionUtils.isNotEmpty(depIds)) {
289 for (Integer depId : new HashSet<>(depIds)) {
290 result.add(departmentDao.getDepartmentById(depId));
291 }
292 }
293 return result;
294 }
295
296 private List<RuleListDTO> toRuleListDTOs(Iterator<Object[]> it) {
297
298 Set<String> managedProgramCodes = programStrategyService.getManagedProgramCodesByQuserId(SecurityContextHelper.getQuadrigeUserId());
299 Set<String> writableProgramCodes = programStrategyService.getWritableProgramCodesByQuserId(SecurityContextHelper.getQuadrigeUserId());
300
301 List<RuleListDTO> result = Lists.newArrayList();
302 TimeZone dbTimezone = config.getDbTimezone();
303
304 while (it.hasNext()) {
305 Object[] source = it.next();
306 RuleListDTO ruleList = toRuleListDTO(Arrays.asList(source).iterator(), dbTimezone);
307
308 if (fillAndValidRuleList(ruleList, managedProgramCodes, writableProgramCodes))
309
310 result.add(ruleList);
311 }
312
313 return result;
314 }
315
316 private RuleListDTO toRuleListDTO(Iterator<Object> source, TimeZone dbTimezone) {
317 RuleListDTO result = ReefDbBeanFactory.newRuleListDTO();
318 result.setCode((String) source.next());
319 result.setActive(Daos.safeConvertToBoolean(source.next()));
320
321 LocalDate startDate = Dates.convertToLocalDate(Daos.convertToDate(source.next()), dbTimezone);
322 result.setStartMonth(
323 Optional.ofNullable(startDate)
324 .map(LocalDate::getMonthValue)
325 .flatMap(month -> systemService.getMonths().stream().filter(monthDTO -> monthDTO.getId().equals(month)).findFirst())
326 .orElse(null)
327 );
328
329 LocalDate endDate = Dates.convertToLocalDate(Daos.convertToDate(source.next()), dbTimezone);
330 result.setEndMonth(
331 Optional.ofNullable(endDate)
332 .map(LocalDate::getMonthValue)
333 .flatMap(month -> systemService.getMonths().stream().filter(monthDTO -> monthDTO.getId().equals(month)).findFirst())
334 .orElse(null)
335 );
336
337 result.setDescription((String) source.next());
338 result.setStatus(Daos.getStatus((String) source.next()));
339 result.setCreationDate(Daos.convertToDate(source.next()));
340 result.setUpdateDate(Daos.convertToDate(source.next()));
341
342 return result;
343 }
344
345 private void beanToEntity(RuleListDTO source, RuleList target, int quserId, TimeZone dbTimezone) {
346
347 target.setRuleListDc(source.getDescription());
348 target.setRuleListIsActive(Daos.convertToString(source.isActive()));
349
350
351 LocalDate startDate = Optional.ofNullable(source.getStartMonth())
352 .map(monthDTO -> LocalDate.of(LocalDate.now().getYear(), monthDTO.getId(), 1))
353 .orElse(null);
354 target.setRuleListFirstMonth(Dates.convertToDate(startDate, dbTimezone));
355
356 LocalDate endDate = Optional.ofNullable(source.getEndMonth())
357 .map(monthDTO -> LocalDate.of(LocalDate.now().getYear(), monthDTO.getId(), 1).plusMonths(1).minusDays(1))
358 .orElse(null);
359 target.setRuleListLastMonth(Dates.convertToDate(endDate, dbTimezone));
360
361
362 if (ReefDbBeans.isLocalStatus(source.getStatus())) {
363 target.setUpdateDt(newUpdateTimestamp());
364 }
365
366
367 if (target.getRuleListCreationDt() == null) {
368 target.setRuleListCreationDt(newCreateDate());
369 }
370
371
372 if (CollectionUtils.isEmpty(target.getQusers())) {
373
374 Quser quser = load(QuserImpl.class, quserId);
375 target.setQusers(Sets.newHashSet(quser));
376 } else if (ReefDbBeans.findByProperty(target.getQusers(), "quserId", quserId) == null) {
377
378 Quser quser = load(QuserImpl.class, quserId);
379 target.getQusers().add(quser);
380 }
381
382
383 if (CollectionUtils.isEmpty(target.getRespDepartments())) {
384
385 Quser quser = load(QuserImpl.class, quserId);
386 target.setRespDepartments(Sets.newHashSet(quser.getDepartment()));
387 } else {
388
389 Quser quser = load(QuserImpl.class, quserId);
390 if (ReefDbBeans.findByProperty(target.getRespDepartments(), "depId", quser.getDepartment().getDepId()) == null) {
391 target.getRespDepartments().add(quser.getDepartment());
392 }
393 }
394
395
396 if (source.getPrograms() == null) {
397 target.getPrograms().clear();
398 } else {
399 Daos.replaceEntities(target.getPrograms(),
400 source.getPrograms(),
401 vo -> load(ProgramImpl.class, Objects.requireNonNull(vo).getCode()));
402 }
403
404
405
406
407 if (source.getDepartments() == null) {
408 target.getControledDepartments().clear();
409 } else {
410 Daos.replaceEntities(target.getControledDepartments(),
411 source.getDepartments(),
412 vo -> load(DepartmentImpl.class, Objects.requireNonNull(vo).getId()));
413 }
414
415 }
416
417 }