View Javadoc
1   package fr.ifremer.dali.dao.administration.program;
2   
3   /*
4    * #%L
5    * Dali :: Core
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2014 - 2015 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import com.google.common.collect.ArrayListMultimap;
27  import com.google.common.collect.ImmutableList;
28  import com.google.common.collect.ImmutableListMultimap;
29  import com.google.common.collect.Multimap;
30  import fr.ifremer.dali.dao.administration.strategy.DaliStrategyDao;
31  import fr.ifremer.dali.dao.administration.user.DaliDepartmentDao;
32  import fr.ifremer.dali.dao.administration.user.DaliQuserDao;
33  import fr.ifremer.dali.dao.referential.DaliReferentialDao;
34  import fr.ifremer.dali.dao.technical.Daos;
35  import fr.ifremer.dali.dto.DaliBeanFactory;
36  import fr.ifremer.dali.dto.DaliBeans;
37  import fr.ifremer.dali.dto.configuration.programStrategy.ProgramDTO;
38  import fr.ifremer.dali.dto.configuration.programStrategy.StrategyDTO;
39  import fr.ifremer.dali.dto.referential.DepartmentDTO;
40  import fr.ifremer.dali.dto.referential.LocationDTO;
41  import fr.ifremer.dali.dto.referential.PersonDTO;
42  import fr.ifremer.quadrige3.core.dao.administration.program.*;
43  import fr.ifremer.quadrige3.core.dao.administration.user.DepartmentImpl;
44  import fr.ifremer.quadrige3.core.dao.administration.user.QuserImpl;
45  import fr.ifremer.quadrige3.core.dao.referential.monitoringLocation.MonitoringLocationImpl;
46  import fr.ifremer.quadrige3.core.dao.technical.Assert;
47  import fr.ifremer.quadrige3.core.dao.technical.hibernate.TemporaryDataHelper;
48  import fr.ifremer.quadrige3.core.service.technical.CacheService;
49  import fr.ifremer.quadrige3.ui.core.dto.QuadrigeBeans;
50  import org.apache.commons.collections4.CollectionUtils;
51  import org.apache.commons.collections4.MapUtils;
52  import org.apache.commons.logging.Log;
53  import org.apache.commons.logging.LogFactory;
54  import org.hibernate.Query;
55  import org.hibernate.SessionFactory;
56  import org.hibernate.type.DateType;
57  import org.hibernate.type.IntegerType;
58  import org.hibernate.type.StringType;
59  import org.springframework.beans.factory.annotation.Autowired;
60  import org.springframework.cache.Cache;
61  import org.springframework.dao.DataRetrievalFailureException;
62  import org.springframework.stereotype.Repository;
63  
64  import javax.annotation.Resource;
65  import java.util.*;
66  import java.util.stream.Collectors;
67  
68  /**
69   * <p>DaliProgramDaoImpl class.</p>
70   *
71   */
72  @Repository("daliProgramDao")
73  public class DaliProgramDaoImpl extends ProgramDaoImpl implements DaliProgramDao {
74  
75      /**
76       * Logger.
77       */
78      private static final Log log = LogFactory.getLog(DaliProgramDaoImpl.class);
79  
80      private static final Multimap<String, String> columnNamesByRulesTableNames = ImmutableListMultimap.<String, String>builder()
81              .put("RULE_LIST_PROG", "PROG_CD").build();
82  
83      @Resource(name = "daliStrategyDao")
84      private DaliStrategyDao strategyDao;
85  
86      @Resource(name = "daliQuserDao")
87      protected DaliQuserDao quserDao;
88  
89      @Resource(name = "daliDepartmentDao")
90      protected DaliDepartmentDao departmentDao;
91  
92      @Resource
93      private ProgQuserProgPrivDao progQuserProgPrivDao;
94  
95      @Resource
96      private ProgDepProgPrivDao progDepProgPrivDao;
97  
98      @Resource
99      protected CacheService cacheService;
100 
101     @Resource(name = "daliReferentialDao")
102     protected DaliReferentialDao referentialDao;
103 
104     /**
105      * <p>Constructor for DaliProgramDaoImpl.</p>
106      *
107      * @param sessionFactory a {@link org.hibernate.SessionFactory} object.
108      */
109     @Autowired
110     public DaliProgramDaoImpl(SessionFactory sessionFactory) {
111         super(sessionFactory);
112     }
113 
114     /** {@inheritDoc} */
115     @Override
116     public List<ProgramDTO> getAllPrograms() {
117 
118         Cache cacheByCode = cacheService.getCache(PROGRAM_BY_CODE_CACHE);
119 
120         Iterator<Object[]> rows = queryIterator("allPrograms");
121 
122         List<ProgramDTO> result = new ArrayList<>();
123         while (rows.hasNext()) {
124             ProgramDTO program = toProgramDTO(Arrays.asList(rows.next()).iterator());
125 
126             // Add program privileges
127             getProgramPrivileges(program);
128 
129             result.add(program);
130             cacheByCode.put(program.getCode(), program);
131         }
132 
133         return ImmutableList.copyOf(result);
134     }
135 
136     private void getProgramPrivileges(ProgramDTO program) {
137 
138         // TODO save program privileges, penser à ajouter le recorder par défaut
139 
140         // query the PROG_QUSER_PROG_PRIV table
141         Iterator<Object[]> rows = queryIterator("programPrivilegesForUsersByProgramCode",
142                 "programCode", StringType.INSTANCE, program.getCode());
143 
144         program.setManagerPersons(new ArrayList<>());
145         program.setRecorderPersons(new ArrayList<>());
146         while (rows.hasNext()) {
147             Object[] row = rows.next();
148             Integer privilegeId = (Integer) row[0];
149             Integer quserId = (Integer) row[1];
150 
151             if (privilegeId != null && quserId != null) {
152                 PersonDTO user = quserDao.getUserById(quserId);
153 
154                 if (ProgramPrivilegeIds.MANAGER.getValue().equals(privilegeId)) {
155                     program.addManagerPersons(user);
156                 } else if (ProgramPrivilegeIds.RECORDER.getValue().equals(privilegeId)) {
157                     program.addRecorderPersons(user);
158                 } else {
159                     if (log.isDebugEnabled()) {
160                         log.debug("ProgrammePrivilegeId = " + privilegeId + " is ignored");
161                     }
162                 }
163             }
164         }
165 
166         // query the PROG_DEP_PROG_PRIV table
167         rows = queryIterator("programPrivilegesForDepartmentsByProgramCode",
168                 "programCode", StringType.INSTANCE, program.getCode());
169 
170         program.setRecorderDepartments(new ArrayList<>());
171         while (rows.hasNext()) {
172             Object[] row = rows.next();
173             Integer privilegeId = (Integer) row[0];
174             Integer depId = (Integer) row[1];
175 
176             if (privilegeId != null && depId != null) {
177                 DepartmentDTO department = departmentDao.getDepartmentById(depId);
178 
179                 if (ProgramPrivilegeIds.RECORDER.getValue().equals(privilegeId)) {
180                     program.addRecorderDepartments(department);
181                 } else {
182                     if (log.isDebugEnabled()) {
183                         log.debug("ProgrammePrivilegeId = " + privilegeId + " is ignored");
184                     }
185                 }
186             }
187 
188         }
189     }
190 
191     /** {@inheritDoc} */
192     @Override
193     public ProgramDTO getProgramByCode(String programCode) {
194         Assert.notBlank(programCode);
195 
196         Object[] row = queryUnique("programByCode",
197                 "programCode", StringType.INSTANCE, programCode);
198 
199         if (row == null) {
200             throw new DataRetrievalFailureException("can't load program with code = " + programCode);
201         }
202 
203         return toProgramDTO(Arrays.asList(row).iterator());
204     }
205 
206     /** {@inheritDoc} */
207     @Override
208     public List<ProgramDTO> getProgramsByCampaignId(Integer campaignId) {
209         Iterator<Object[]> rows = queryIterator("programsByCampaignId",
210                 "campaignId", IntegerType.INSTANCE, campaignId);
211 
212         List<ProgramDTO> result = new ArrayList<>();
213         while (rows.hasNext()) {
214             result.add(toProgramDTO(Arrays.asList(rows.next()).iterator()));
215         }
216 
217         return result;
218     }
219 
220     /** {@inheritDoc} */
221     @Override
222     @SuppressWarnings("unchecked")
223     public List<ProgramDTO> getProgramsByCodes(List<String> programCodes) {
224 
225         List<ProgramDTO> result = new ArrayList<>();
226         if (CollectionUtils.isEmpty(programCodes))
227             return result;
228 
229         Iterator<Object[]> rows = createQuery("programsByCodes")
230                 .setParameterList("programCodes", programCodes)
231                 .iterate();
232 
233         while (rows.hasNext()) {
234             result.add(toProgramDTO(Arrays.asList(rows.next()).iterator()));
235         }
236 
237         return result;
238 
239     }
240 
241     /** {@inheritDoc} */
242     @Override
243     public List<ProgramDTO> findProgramsByCodeAndName(List<String> statusCodes, String code, String name) {
244         Query query = createQuery("programsByCodeAndName",
245                 "code", StringType.INSTANCE, code,
246                 "name", StringType.INSTANCE, name);
247 
248         Iterator<Object[]> rows = Daos.queryIteratorWithStatus(query, statusCodes);
249 
250         List<ProgramDTO> result = new ArrayList<>();
251         while (rows.hasNext()) {
252             result.add(toProgramDTO(Arrays.asList(rows.next()).iterator()));
253         }
254 
255         return result;
256     }
257 
258     /** {@inheritDoc} */
259     @Override
260     public List<ProgramDTO> findProgramsByLocationAndDate(List<String> statusCodes, int locationId, Date date) {
261         Query query = createQuery("programsByLocationAndDate",
262                 "locationId", IntegerType.INSTANCE, locationId,
263                 "date", DateType.INSTANCE, date);
264 
265         Iterator<Object[]> rows = Daos.queryIteratorWithStatus(query, statusCodes);
266 
267         List<ProgramDTO> result = new ArrayList<>();
268         while (rows.hasNext()) {
269             result.add(toProgramDTO(Arrays.asList(rows.next()).iterator()));
270         }
271 
272         return result;
273     }
274 
275     /** {@inheritDoc} */
276     @Override
277     public boolean isProgramUsedByRuleList(String programCode) {
278         return executeMultipleCount(columnNamesByRulesTableNames, programCode);
279     }
280 
281     /** {@inheritDoc} */
282     @Override
283     public void saveProgram(ProgramDTO program) {
284         Assert.notNull(program);
285         Assert.notBlank(program.getCode());
286 
287         // Check program already exists
288         Program target = get(program.getCode());
289         if (target == null) {
290             throw new DataRetrievalFailureException(String.format("Program with code %s doesn't exists in local database", program.getCode()));
291         }
292 
293         // Transform to entity
294         programDTOToEntity(program, target);
295 
296         // Save (update only)
297         getSession().update(target);
298 
299         // locations if loaded
300         if (program.isLocationsLoaded() || !program.isLocationsEmpty()) {
301             if (program.isLocationsEmpty()) {
302                 // clear locations
303                 if (!target.getMonLocProgs().isEmpty()) {
304                     target.getMonLocProgs().clear();
305                 }
306             } else {
307 
308                 Multimap<Integer, MonLocProg> remainingMonLocProgs = ArrayListMultimap.create(
309                         DaliBeans.<Integer, MonLocProg>populateByProperty(target.getMonLocProgs(), "monitoringLocation.monLocId")
310                 );
311 
312                 for (LocationDTO locationDTO : program.getLocations()) {
313                     boolean exists = remainingMonLocProgs.containsKey(locationDTO.getId());
314                     if (!exists) {
315                         // create new MonLocProg
316                         MonLocProg monLocProg = MonLocProg.Factory.newInstance(target, load(MonitoringLocationImpl.class, locationDTO.getId()));
317                         Integer monLocProgId = TemporaryDataHelper.getNewNegativeIdForTemporaryData(getSession(), monLocProg.getClass());
318                         monLocProg.setMonLocProgId(monLocProgId);
319                         getSession().save(monLocProg);
320                         target.addMonLocProgs(monLocProg);
321                     } else {
322                         remainingMonLocProgs.removeAll(locationDTO.getId());
323                     }
324                 }
325 
326                 // remove unused MonLocProgs
327                 if (!remainingMonLocProgs.isEmpty()) {
328                     target.getMonLocProgs().removeAll(remainingMonLocProgs.values());
329                     // delete
330                     deleteProgramLocations(program.getCode(), remainingMonLocProgs.keySet());
331 
332                     // remove locations from strategies
333                     if (!program.isStrategiesEmpty()) {
334                         for (StrategyDTO strategy : program.getStrategies()) {
335                             if (!strategy.isAppliedStrategiesEmpty()) {
336                                 strategy.getAppliedStrategies().removeIf(lieu -> remainingMonLocProgs.containsKey(lieu.getId()));
337                             }
338                         }
339                     }
340                 }
341             }
342         }
343 
344         getSession().flush();
345         getSession().clear();
346 
347         // save strategies if loaded or strategies to save
348         if (program.isStrategiesLoaded() || !program.isStrategiesEmpty()) {
349             strategyDao.saveStrategies(program);
350 
351             // Make sure to flush the program
352             getSession().flush();
353             getSession().clear();
354         }
355     }
356 
357     /** {@inheritDoc} */
358     @Override
359     public void remove(String programCode) {
360         Assert.notBlank(programCode);
361 
362         // delete strategies
363         strategyDao.removeByProgramCode(programCode);
364 
365         // delete Program
366         super.remove(programCode);
367 
368         getSession().flush();
369         getSession().clear();
370     }
371 
372     /** {@inheritDoc} */
373     @Override
374     public void deleteProgramLocations(String programCode, Collection<Integer> monitoringLocationIds) {
375         Assert.notBlank(programCode);
376         if (monitoringLocationIds == null) return;
377         Set<Integer> idsToDelete = monitoringLocationIds.stream().filter(Objects::nonNull).collect(Collectors.toSet());
378         if (CollectionUtils.isEmpty(idsToDelete)) return;
379 
380         // delete monLocProgs
381         Query query = createQuery("deleteMonitoringLocationsByProgramCode", "programCode", StringType.INSTANCE, programCode);
382         query.setParameterList("monitoringLocationIds", idsToDelete);
383         query.executeUpdate();
384 
385         // delete applied strategies
386         strategyDao.deleteAppliedStrategies(programCode, idsToDelete);
387 
388         getSession().flush();
389         getSession().clear();
390     }
391 
392     /* -- INTERNAL METHODS -- */
393 
394     private ProgramDTO toProgramDTO(Iterator<Object> source) {
395         ProgramDTO result = DaliBeanFactory.newProgramDTO();
396 
397         // Code
398         result.setCode((String) source.next());
399 
400         // Name
401         result.setName((String) source.next());
402 
403         // Description
404         result.setDescription((String) source.next());
405 
406         // IsDepartmentHermetic
407         result.setDepartmentHermetic(Daos.safeConvertToBoolean(source.next(), false));
408 
409         // Local status
410         result.setStatus(referentialDao.getStatusByCode((String) source.next()));
411 
412         result.setComment((String) source.next());
413         result.setCreationDate(Daos.convertToDate(source.next()));
414         result.setUpdateDate(Daos.convertToDate(source.next()));
415 
416         return result;
417     }
418 
419     private void programDTOToEntity(final ProgramDTO source, final Program target) {
420         Assert.notNull(source);
421         Assert.notNull(target);
422 
423         target.setProgNm(source.getName());
424         target.setProgDc(source.getComment());
425         target.setIsDepartmentHermetic(Daos.convertToString(source.isDepartmentHermetic()));
426 
427         // Set update date (only if local program)
428         if (QuadrigeBeans.isLocalStatus(source.getStatus())) {
429             target.setUpdateDt(newUpdateTimestamp());
430         }
431 
432         // User privileges
433         {
434             Map<ProgQuserProgPrivPK, ProgQuserProgPriv> quserProvPrivs = new HashMap<>();
435 
436             // Manager user
437             if (CollectionUtils.isNotEmpty(source.getManagerPersons())) {
438                 for (PersonDTO manager : source.getManagerPersons()) {
439                     ProgQuserProgPriv progQuserProgPriv = loadProgQuserProgPriv(target, manager.getId(), ProgramPrivilegeIds.MANAGER);
440                     quserProvPrivs.put(progQuserProgPriv.getProgQuserProgPrivPk(), progQuserProgPriv);
441                 }
442             }
443 
444             // Recorder user
445             if (CollectionUtils.isNotEmpty(source.getRecorderPersons())) {
446                 for (PersonDTO manager : source.getRecorderPersons()) {
447                     ProgQuserProgPriv progQuserProgPriv = loadProgQuserProgPriv(target, manager.getId(), ProgramPrivilegeIds.RECORDER);
448                     quserProvPrivs.put(progQuserProgPriv.getProgQuserProgPrivPk(), progQuserProgPriv);
449                 }
450             }
451 
452             // Viewer user : keep all existing rights
453             if (CollectionUtils.isNotEmpty(target.getProgQuserProgPrivs())) {
454                 for (ProgQuserProgPriv quserProgPriv : target.getProgQuserProgPrivs()) {
455                     ProgramPrivilege programPrivilege = quserProgPriv.getProgQuserProgPrivPk().getProgramPrivilege();
456                     if (Objects.equals(programPrivilege.getProgPrivId(), ProgramPrivilegeIds.VIEWER.getValue())) {
457                         quserProvPrivs.put(quserProgPriv.getProgQuserProgPrivPk(), quserProgPriv);
458                     }
459                 }
460             }
461 
462             // Update entity list
463             if (MapUtils.isEmpty(quserProvPrivs)) {
464                 if (CollectionUtils.isNotEmpty(target.getProgQuserProgPrivs())) {
465                     target.getProgQuserProgPrivs().clear();
466                 }
467             } else {
468                 target.getProgQuserProgPrivs().clear();
469                 target.getProgQuserProgPrivs().addAll(quserProvPrivs.values());
470             }
471         }
472 
473         // Department privileges
474         {
475             Map<ProgDepProgPrivPK, ProgDepProgPriv> depProvPrivs = new HashMap<>();
476 
477             // Manager departments : keep all existing rights
478             // TODO - en fonction de la reponse à la question mantis #28223
479             if (CollectionUtils.isNotEmpty(target.getProgDepProgPrivs())) {
480                 for (ProgDepProgPriv depProgPriv : target.getProgDepProgPrivs()) {
481                     ProgramPrivilege programPrivilege = depProgPriv.getProgDepProgPrivPk().getProgramPrivilege();
482                     if (Objects.equals(programPrivilege.getProgPrivId(), ProgramPrivilegeIds.MANAGER.getValue())) {
483                         depProvPrivs.put(depProgPriv.getProgDepProgPrivPk(), depProgPriv);
484                     }
485                 }
486             }
487 
488             // Recorder departments
489             if (CollectionUtils.isNotEmpty(source.getRecorderDepartments())) {
490                 for (DepartmentDTO departmentDTO : source.getRecorderDepartments()) {
491                     ProgDepProgPriv progDepProgPriv = loadProgDepProgPriv(target, departmentDTO.getId(), ProgramPrivilegeIds.RECORDER);
492                     depProvPrivs.put(progDepProgPriv.getProgDepProgPrivPk(), progDepProgPriv);
493                 }
494             }
495 
496             // Viewer user : keep all existing rights
497             if (CollectionUtils.isNotEmpty(target.getProgDepProgPrivs())) {
498                 for (ProgDepProgPriv depProgPriv : target.getProgDepProgPrivs()) {
499                     ProgramPrivilege programPrivilege = depProgPriv.getProgDepProgPrivPk().getProgramPrivilege();
500                     if (Objects.equals(programPrivilege.getProgPrivId(), ProgramPrivilegeIds.VIEWER.getValue())) {
501                         depProvPrivs.put(depProgPriv.getProgDepProgPrivPk(), depProgPriv);
502                     }
503                 }
504             }
505 
506             // Update entity list
507             if (MapUtils.isEmpty(depProvPrivs)) {
508                 if (CollectionUtils.isNotEmpty(target.getProgDepProgPrivs())) {
509                     target.getProgDepProgPrivs().clear();
510                 }
511             } else {
512                 target.getProgDepProgPrivs().clear();
513                 target.getProgDepProgPrivs().addAll(depProvPrivs.values());
514             }
515         }
516 
517     }
518 
519     /**
520      * Retrieves the entity object that is associated with the specified value object
521      * from the object store. If no such entity object exists in the object store,
522      * a new, blank entity is created
523      */
524     private ProgQuserProgPriv loadProgQuserProgPriv(Program program, int quserId, ProgramPrivilegeIds programPrivilegeId) {
525         ProgQuserProgPrivPK pk = new ProgQuserProgPrivPK();
526 
527         pk.setProgram((ProgramImpl) program);
528         pk.setQuser(load(QuserImpl.class, quserId));
529         pk.setProgramPrivilege(load(ProgramPrivilegeImpl.class, programPrivilegeId.getValue()));
530 
531         ProgQuserProgPriv target = progQuserProgPrivDao.get(pk);
532         if (target == null) {
533             target = ProgQuserProgPriv.Factory.newInstance();
534             target.setProgQuserProgPrivPk(pk);
535         }
536         return target;
537     }
538 
539     private ProgDepProgPriv loadProgDepProgPriv(Program program, int depId, ProgramPrivilegeIds programPrivilegeId) {
540         ProgDepProgPrivPK pk = new ProgDepProgPrivPK();
541 
542         pk.setProgram((ProgramImpl) program);
543         pk.setDepartment(load(DepartmentImpl.class, depId));
544         pk.setProgramPrivilege(load(ProgramPrivilegeImpl.class, programPrivilegeId.getValue()));
545 
546         ProgDepProgPriv target = progDepProgPrivDao.get(pk);
547         if (target == null) {
548             target = ProgDepProgPriv.Factory.newInstance();
549             target.setProgDepProgPrivPk(pk);
550         }
551         return target;
552     }
553 }