View Javadoc
1   package net.sumaris.core.dao.administration.programStrategy;
2   
3   /*-
4    * #%L
5    * SUMARiS:: Core
6    * %%
7    * Copyright (C) 2018 SUMARiS Consortium
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   *
19   * You should have received a copy of the GNU General Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  import com.google.common.base.Preconditions;
26  import com.google.common.collect.ImmutableList;
27  import net.sumaris.core.dao.referential.ReferentialDao;
28  import net.sumaris.core.dao.referential.taxon.TaxonNameDao;
29  import net.sumaris.core.dao.technical.hibernate.HibernateDaoSupport;
30  import net.sumaris.core.dao.technical.model.IEntity;
31  import net.sumaris.core.model.administration.programStrategy.AcquisitionLevel;
32  import net.sumaris.core.model.administration.programStrategy.PmfmStrategy;
33  import net.sumaris.core.model.administration.programStrategy.Program;
34  import net.sumaris.core.model.administration.programStrategy.Strategy;
35  import net.sumaris.core.model.referential.Status;
36  import net.sumaris.core.model.referential.StatusEnum;
37  import net.sumaris.core.model.referential.gear.Gear;
38  import net.sumaris.core.model.referential.pmfm.Parameter;
39  import net.sumaris.core.model.referential.pmfm.Pmfm;
40  import net.sumaris.core.util.Beans;
41  import net.sumaris.core.vo.administration.programStrategy.*;
42  import net.sumaris.core.vo.referential.ParameterValueType;
43  import net.sumaris.core.vo.referential.ReferentialVO;
44  import net.sumaris.core.vo.referential.TaxonGroupVO;
45  import org.apache.commons.collections4.CollectionUtils;
46  import org.slf4j.Logger;
47  import org.slf4j.LoggerFactory;
48  import org.springframework.beans.factory.annotation.Autowired;
49  import org.springframework.stereotype.Repository;
50  
51  import javax.annotation.PostConstruct;
52  import javax.persistence.EntityManager;
53  import javax.persistence.LockModeType;
54  import javax.persistence.criteria.*;
55  import java.sql.Timestamp;
56  import java.util.Comparator;
57  import java.util.List;
58  import java.util.Objects;
59  import java.util.stream.Collectors;
60  
61  @Repository("strategyDao")
62  public class StrategyDaoImpl extends HibernateDaoSupport implements StrategyDao {
63  
64      /**
65       * Logger.
66       */
67      private static final Logger log =
68              LoggerFactory.getLogger(StrategyDaoImpl.class);
69  
70  
71      @Autowired
72      private ReferentialDao referentialDao;
73  
74      @Autowired
75      private TaxonNameDao taxonNameDao;
76  
77      private int unitIdNone;
78  
79      @PostConstruct
80      protected void init() {
81          this.unitIdNone = config.getUnitIdNone();
82      }
83  
84      @Override
85      public List<StrategyVO> findByProgram(int programId, StrategyFetchOptions fetchOptions) {
86          CriteriaBuilder builder = entityManager.getCriteriaBuilder();
87          CriteriaQuery<Strategy> query = builder.createQuery(Strategy.class);
88          Root<Strategy> root = query.from(Strategy.class);
89  
90          ParameterExpression<Integer> programIdParam = builder.parameter(Integer.class);
91  
92          query.select(root)
93                  .where(
94                          builder.equal(root.get(Strategy.Fields.PROGRAM).get(Program.Fields.ID), programIdParam));
95  
96          // Sort by rank order
97          query.orderBy(builder.asc(root.get(Strategy.Fields.ID)));
98  
99          return getEntityManager()
100                 .createQuery(query)
101                 .setParameter(programIdParam, programId)
102                 .getResultStream()
103                 .map(s -> this.toStrategyVO(s, fetchOptions))
104                 .collect(Collectors.toList());
105     }
106 
107     @Override
108     public List<PmfmStrategyVO> getPmfmStrategies(int strategyId) {
109 
110         CriteriaBuilder builder = entityManager.getCriteriaBuilder();
111         CriteriaQuery<PmfmStrategy> query = builder.createQuery(PmfmStrategy.class);
112         Root<PmfmStrategy> root = query.from(PmfmStrategy.class);
113 
114         ParameterExpression<Integer> strategyIdParam = builder.parameter(Integer.class);
115 
116         Join<PmfmStrategy, Strategy> strategyInnerJoin = root.join(PmfmStrategy.Fields.STRATEGY, JoinType.INNER);
117 
118         query.select(root)
119                 .where(builder.equal(strategyInnerJoin.get(Strategy.Fields.ID), strategyIdParam))
120                 // Sort by rank order
121                 .orderBy(builder.asc(root.get(PmfmStrategy.Fields.RANK_ORDER)));
122 
123         return getEntityManager()
124                 .createQuery(query)
125                 .setParameter(strategyIdParam, strategyId)
126                 .getResultStream()
127                 .map(this::toPmfmStrategyVO)
128                 .collect(Collectors.toList());
129     }
130 
131     @Override
132     public List<PmfmStrategyVO> getPmfmStrategiesByAcquisitionLevel(int programId, int acquisitionLevelId) {
133         CriteriaBuilder builder = entityManager.getCriteriaBuilder();
134         CriteriaQuery<PmfmStrategy> query = builder.createQuery(PmfmStrategy.class);
135         Root<PmfmStrategy> root = query.from(PmfmStrategy.class);
136 
137         ParameterExpression<Integer> programIdParam = builder.parameter(Integer.class);
138         ParameterExpression<Integer> acquisitionLevelIdParam = builder.parameter(Integer.class);
139 
140         Join<PmfmStrategy, Strategy> strategyInnerJoin = root.join(PmfmStrategy.Fields.STRATEGY, JoinType.INNER);
141 
142         query.select(root)
143                 .where(
144                         builder.and(
145                                 builder.equal(strategyInnerJoin.get(Strategy.Fields.PROGRAM).get(Program.Fields.ID), programIdParam),
146                                 builder.equal(root.get(PmfmStrategy.Fields.ACQUISITION_LEVEL).get(AcquisitionLevel.Fields.ID), acquisitionLevelIdParam)
147                         ));
148 
149         // Sort by rank order
150         query.orderBy(builder.asc(root.get(PmfmStrategy.Fields.RANK_ORDER)));
151 
152         return getEntityManager()
153                 .createQuery(query)
154                 .setParameter(programIdParam, programId)
155                 .setParameter(acquisitionLevelIdParam, acquisitionLevelId)
156                 .getResultStream()
157                 .map(this::toPmfmStrategyVO)
158                 .collect(Collectors.toList());
159     }
160 
161     @Override
162     public List<ReferentialVO> getGears(int strategyId) {
163         CriteriaBuilder builder = entityManager.getCriteriaBuilder();
164         CriteriaQuery<Gear> query = builder.createQuery(Gear.class);
165         Root<Gear> root = query.from(Gear.class);
166 
167         ParameterExpression<Integer> strategyIdParam = builder.parameter(Integer.class);
168 
169         Join<Gear, Strategy> gearInnerJoin = root.joinList(Gear.Fields.STRATEGIES, JoinType.INNER);
170 
171         query.select(root)
172                 .where(
173                         builder.and(
174                                 // strategy
175                                 builder.equal(gearInnerJoin.get(Strategy.Fields.ID), strategyIdParam),
176                                 // Status (temporary or valid)
177                                 builder.in(root.get(Gear.Fields.STATUS).get(Status.Fields.ID)).value(ImmutableList.of(StatusEnum.ENABLE.getId(), StatusEnum.TEMPORARY.getId()))
178                         ));
179 
180         // Sort by label
181         query.orderBy(builder.asc(root.get(Gear.Fields.LABEL)));
182 
183         return getEntityManager()
184                 .createQuery(query)
185                 .setParameter(strategyIdParam, strategyId)
186                 .getResultStream()
187                 .map(referentialDao::toReferentialVO)
188                 .collect(Collectors.toList());
189     }
190 
191     @Override
192     public List<TaxonGroupStrategyVO> getTaxonGroupStrategies(int strategyId) {
193         return getTaxonGroups(load(Strategy.class, strategyId));
194     }
195 
196     @Override
197     public List<TaxonNameStrategyVO> getTaxonNameStrategies(int strategyId) {
198         return getTaxonNames(load(Strategy.class, strategyId));
199     }
200 
201 
202     /* -- protected methods -- */
203 
204     protected StrategyVO toStrategyVO(Strategy source, StrategyFetchOptions fetchOptions) {
205         if (source == null) return null;
206 
207         StrategyVOstration/programStrategy/StrategyVO.html#StrategyVO">StrategyVO target = new StrategyVO();
208 
209         Beans.copyProperties(source, target);
210 
211         // Program
212         target.setProgramId(source.getProgram().getId());
213 
214         // Status id
215         target.setStatusId(source.getStatus().getId());
216 
217         // Gears
218         if (CollectionUtils.isNotEmpty(source.getGears())) {
219             List<ReferentialVO> gears = source.getGears()
220                     .stream()
221                     .map(referentialDao::toReferentialVO)
222                     .filter(Objects::nonNull)
223                     .collect(Collectors.toList());
224             target.setGears(gears);
225         }
226 
227         // Taxon groups
228         target.setTaxonGroups(getTaxonGroups(source));
229 
230         // Taxon names
231         target.setTaxonNames(getTaxonNames(source));
232 
233         // Pmfm strategies
234         if (CollectionUtils.isNotEmpty(source.getPmfmStrategies())) {
235             List<PmfmStrategyVO> pmfmStrategies = source.getPmfmStrategies()
236                     .stream()
237                     // Transform to VO
238                     .map(ps -> toPmfmStrategyVO(ps, fetchOptions))
239                     .filter(Objects::nonNull)
240                     // Sort by acquisitionLevel and rankOrder
241                     .sorted(Comparator.comparing(ps -> String.format("%s#%s", ps.getAcquisitionLevel(), ps.getRankOrder())))
242                     .collect(Collectors.toList());
243             target.setPmfmStrategies(pmfmStrategies);
244         }
245 
246         return target;
247     }
248 
249     protected PmfmStrategyVO toPmfmStrategyVO(PmfmStrategy source) {
250         return toPmfmStrategyVO(source, StrategyFetchOptions.builder().withPmfmStrategyInheritance(false).build());
251     }
252 
253     protected PmfmStrategyVO toPmfmStrategyVO(PmfmStrategy source, StrategyFetchOptions fetchOptions) {
254         return toPmfmStrategyVO(source, fetchOptions.isWithPmfmStrategyInheritance());
255     }
256 
257     @Override
258     public PmfmStrategyVO toPmfmStrategyVO(PmfmStrategy source, boolean enablePmfmInheritance) {
259         if (source == null) return null;
260 
261         Pmfm pmfm = source.getPmfm();
262         Preconditions.checkNotNull(pmfm);
263 
264         PmfmStrategyVOtion/programStrategy/PmfmStrategyVO.html#PmfmStrategyVO">PmfmStrategyVO target = new PmfmStrategyVO();
265 
266         // Copy properties, from Pmfm first (if inherit enable), then from source
267         if (enablePmfmInheritance) {
268             Beans.copyProperties(pmfm, target);
269         }
270         Beans.copyProperties(source, target);
271 
272         // Set some attributes from Pmfm
273         target.setPmfmId(pmfm.getId());
274 
275         // Apply default values from Pmfm
276         if (pmfm.getMethod() != null) {
277             target.setMethodId(pmfm.getMethod().getId());
278         }
279         if (target.getMinValue() == null) {
280             target.setMinValue(pmfm.getMinValue());
281         }
282         if (target.getMaxValue() == null) {
283             target.setMaxValue(pmfm.getMaxValue());
284         }
285         if (target.getDefaultValue() == null) {
286             target.setDefaultValue(pmfm.getDefaultValue());
287         }
288 
289         // Parameter name
290         Parameter parameter = pmfm.getParameter();
291         target.setName(parameter.getName());
292 
293         // Parameter Type
294         ParameterValueType type = ParameterValueType.fromPmfm(pmfm);
295         target.setType(type.name().toLowerCase());
296 
297         // Unit symbol
298         if (pmfm.getUnit() != null && pmfm.getUnit().getId().intValue() != unitIdNone) {
299             target.setUnit(pmfm.getUnit().getLabel());
300         }
301 
302         // Acquisition Level
303         if (source.getAcquisitionLevel() != null) {
304             target.setAcquisitionLevel(source.getAcquisitionLevel().getLabel());
305         }
306 
307         // Qualitative values
308         if (CollectionUtils.isNotEmpty(parameter.getQualitativeValues())) {
309             List<ReferentialVO> qualitativeValues = parameter.getQualitativeValues()
310                     .stream()
311                     .map(referentialDao::toReferentialVO)
312                     .collect(Collectors.toList());
313             target.setQualitativeValues(qualitativeValues);
314         }
315 
316         // Gears
317         if (CollectionUtils.isNotEmpty(source.getGears())) {
318             List<String> gears = source.getGears()
319                     .stream()
320                     .map(Gear::getLabel)
321                     .filter(Objects::nonNull)
322                     .collect(Collectors.toList());
323             target.setGears(gears);
324         }
325 
326         // Taxon groups
327         if (CollectionUtils.isNotEmpty(source.getTaxonGroups())) {
328             List<Integer> taxonGroupIds = source.getTaxonGroups()
329                     .stream()
330                     .map(IEntity::getId)
331                     .collect(Collectors.toList());
332             target.setTaxonGroupIds(taxonGroupIds);
333         }
334 
335         // Reference taxons
336         if (CollectionUtils.isNotEmpty(source.getReferenceTaxons())) {
337             List<Integer> referenceTaxonIds = source.getReferenceTaxons()
338                     .stream()
339                     .map(IEntity::getId)
340                     .collect(Collectors.toList());
341             target.setReferenceTaxonIds(referenceTaxonIds);
342         }
343 
344         return target;
345     }
346 
347     @Override
348     public List<StrategyVO> saveByProgramId(int programId, List<StrategyVO> sources) {
349         // Load parent entity
350         Program parent = get(Program.class, programId);
351 
352         // Remember existing entities
353         final List<Integer> sourcesIdsToRemove = Beans.collectIds(Beans.getList(parent.getStrategies()));
354 
355         // Save each entities
356         List<StrategyVO> result = sources.stream().map(source -> {
357             source.setProgramId(programId);
358             if (source.getId() != null) {
359                 sourcesIdsToRemove.remove(source.getId());
360             }
361             return save(source);
362         }).collect(Collectors.toList());
363 
364         // Remove unused entities
365         if (CollectionUtils.isNotEmpty(sourcesIdsToRemove)) {
366             sourcesIdsToRemove.forEach(this::delete);
367         }
368 
369         return result;
370     }
371 
372     @Override
373     public StrategyVO"../../../../../../net/sumaris/core/vo/administration/programStrategy/StrategyVO.html#StrategyVO">StrategyVO save(StrategyVO source) {
374         Preconditions.checkNotNull(source);
375         Preconditions.checkNotNull(source.getProgramId(), "Missing 'programId'");
376         Preconditions.checkNotNull(source.getLabel(), "Missing 'label'");
377         Preconditions.checkNotNull(source.getName(), "Missing 'name'");
378         Preconditions.checkNotNull(source.getStatusId(), "Missing 'statusId'");
379 
380         EntityManager entityManager = getEntityManager();
381         Strategy entity = null;
382         if (source.getId() != null) {
383             entity = get(Strategy.class, source.getId());
384         }
385         boolean isNew = (entity == null);
386         if (isNew) {
387             entity = new Strategy();
388         }
389 
390         // If new
391         if (isNew) {
392             // Set default status to Temporary
393             if (source.getStatusId() == null) {
394                 source.setStatusId(config.getStatusIdTemporary());
395             }
396         }
397         // If update
398         else {
399 
400             // Check update date
401             checkUpdateDateForUpdate(source, entity);
402 
403             // Lock entityName
404             lockForUpdate(entity, LockModeType.PESSIMISTIC_WRITE);
405         }
406 
407         strategyVOToEntity(source, entity, true);
408 
409         // Update update_dt
410         Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
411         entity.setUpdateDate(newUpdateDate);
412 
413         // Save entity
414         if (isNew) {
415             // Force creation date
416             entity.setCreationDate(newUpdateDate);
417             source.setCreationDate(newUpdateDate);
418 
419             entityManager.persist(entity);
420             source.setId(entity.getId());
421         } else {
422             entityManager.merge(entity);
423         }
424 
425         source.setUpdateDate(newUpdateDate);
426 
427         // Save pmfm stratgeies
428         //saveProperties(source.getProperties(), entity, newUpdateDate);
429 
430         //getEntityManager().flush();
431         //getEntityManager().clear();
432 
433         return source;
434     }
435 
436     public void delete(int id) {
437         log.debug(String.format("Deleting strategy {id=%s}...", id));
438         delete(Strategy.class, id);
439     }
440 
441     /* -- protected method -- */
442 
443     protected void strategyVOToEntity(StrategyVO source, Strategy target, boolean copyIfNull) {
444 
445 
446         Beans.copyProperties(source, target);
447 
448         // Program
449         if (copyIfNull || source.getProgramId() != null) {
450             if (source.getProgramId() == null) {
451                 target.setProgram(null);
452             }
453             else {
454                 target.setProgram(load(Program.class, source.getProgramId()));
455             }
456         }
457 
458         // Status
459         if (copyIfNull || source.getStatusId() != null) {
460             if (source.getStatusId() == null) {
461                 target.setStatus(null);
462             }
463             else {
464                 target.setStatus(load(Status.class, source.getStatusId()));
465             }
466         }
467 
468     }
469 
470     protected List<TaxonNameStrategyVO> getTaxonNames(Strategy source) {
471         if (CollectionUtils.isEmpty(source.getReferenceTaxons())) return null;
472 
473         return source.getReferenceTaxons()
474                 .stream()
475                 // Sort by priority level (or if not set, by id)
476                 .sorted(Comparator.comparingInt(item -> item.getPriorityLevel() != null ?
477                         item.getPriorityLevel().intValue() :
478                         item.getReferenceTaxon().getId().intValue()))
479                 .map(item -> {
480                     TaxonNameStrategyVOprogramStrategy/TaxonNameStrategyVO.html#TaxonNameStrategyVO">TaxonNameStrategyVO target = new TaxonNameStrategyVO();
481                     target.setStrategyId(source.getId());
482 
483                     // Priority level
484                     target.setPriorityLevel(item.getPriorityLevel());
485 
486                     // Taxon name
487                     target.setTaxonName(taxonNameDao.getTaxonNameReferent(item.getReferenceTaxon().getId()));
488                     return target;
489                 })
490                 .collect(Collectors.toList());
491     }
492 
493     protected List<TaxonGroupStrategyVO> getTaxonGroups(Strategy source) {
494         if (CollectionUtils.isEmpty(source.getTaxonGroups())) return null;
495         return source.getTaxonGroups()
496                 .stream()
497                 // Sort by priority level (or if not set, by id)
498                 .sorted(Comparator.comparingInt((item) -> item.getPriorityLevel() != null ?
499                         item.getPriorityLevel().intValue() :
500                         item.getTaxonGroup().getId().intValue()))
501                 .map(item -> {
502                     TaxonGroupStrategyVOrogramStrategy/TaxonGroupStrategyVO.html#TaxonGroupStrategyVO">TaxonGroupStrategyVO target = new TaxonGroupStrategyVO();
503                     target.setStrategyId(source.getId());
504 
505                     // Priority level
506                     target.setPriorityLevel(item.getPriorityLevel());
507 
508                     // Taxon group
509                     TaxonGroupVOrential/TaxonGroupVO.html#TaxonGroupVO">TaxonGroupVO tg = new TaxonGroupVO();
510                     Beans.copyProperties(item.getTaxonGroup(), tg);
511                     tg.setStatusId(item.getTaxonGroup().getStatus().getId());
512                     target.setTaxonGroup(tg);
513 
514                     return target;
515                 })
516                 .collect(Collectors.toList());
517     }
518 }