View Javadoc
1   package fr.ifremer.reefdb.dao.data.samplingoperation;
2   
3   /*
4    * #%L
5    * Reef DB :: 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.Lists;
27  import fr.ifremer.quadrige3.core.dao.administration.program.Program;
28  import fr.ifremer.quadrige3.core.dao.administration.user.DepartmentImpl;
29  import fr.ifremer.quadrige3.core.dao.data.samplingoperation.SamplingOperation;
30  import fr.ifremer.quadrige3.core.dao.data.samplingoperation.SamplingOperationDaoImpl;
31  import fr.ifremer.quadrige3.core.dao.data.survey.Survey;
32  import fr.ifremer.quadrige3.core.dao.data.survey.SurveyImpl;
33  import fr.ifremer.quadrige3.core.dao.referential.*;
34  import fr.ifremer.quadrige3.core.dao.referential.monitoringLocation.PositionningSystemImpl;
35  import fr.ifremer.quadrige3.core.dao.system.*;
36  import fr.ifremer.quadrige3.core.dao.technical.Assert;
37  import fr.ifremer.quadrige3.core.dao.technical.Daos;
38  import fr.ifremer.reefdb.config.ReefDbConfiguration;
39  import fr.ifremer.reefdb.dao.administration.user.ReefDbDepartmentDao;
40  import fr.ifremer.reefdb.dao.data.measurement.ReefDbMeasurementDao;
41  import fr.ifremer.reefdb.dao.data.photo.ReefDbPhotoDao;
42  import fr.ifremer.reefdb.dao.referential.ReefDbReferentialDao;
43  import fr.ifremer.reefdb.dao.referential.ReefDbSamplingEquipmentDao;
44  import fr.ifremer.reefdb.dao.referential.ReefDbUnitDao;
45  import fr.ifremer.reefdb.dao.technical.Geometries;
46  import fr.ifremer.reefdb.dto.ReefDbBeanFactory;
47  import fr.ifremer.reefdb.dto.ReefDbBeans;
48  import fr.ifremer.reefdb.dto.data.measurement.MeasurementDTO;
49  import fr.ifremer.reefdb.dto.data.sampling.SamplingOperationDTO;
50  import fr.ifremer.reefdb.service.ReefDbDataContext;
51  import org.apache.commons.collections4.CollectionUtils;
52  import org.hibernate.Session;
53  import org.hibernate.SessionFactory;
54  import org.hibernate.type.DateType;
55  import org.hibernate.type.IntegerType;
56  import org.springframework.beans.factory.InitializingBean;
57  import org.springframework.beans.factory.annotation.Autowired;
58  import org.springframework.dao.DataIntegrityViolationException;
59  import org.springframework.stereotype.Repository;
60  
61  import javax.annotation.Resource;
62  import java.util.*;
63  
64  /**
65   * <p>ReefDbSamplingOperationDaoImpl class.</p>
66   *
67   * @author Ludovic
68   */
69  @Repository("reefDbSamplingOperationDao")
70  public class ReefDbSamplingOperationDaoImpl extends SamplingOperationDaoImpl implements ReefDbSamplingOperationDao, InitializingBean {
71  
72  //    private final static Log LOG = LogFactory.getLog(ReefDbSamplingOperationDaoImpl.class);
73  
74      @Resource(name = "reefDbReferentialDao")
75      protected ReefDbReferentialDao referentialDao;
76  
77      @Resource(name = "reefDbSamplingEquipmentDao")
78      protected ReefDbSamplingEquipmentDao samplingEquipmentDao;
79  
80      @Resource(name = "reefDbDepartmentDao")
81      protected ReefDbDepartmentDao departmentDao;
82  
83      @Resource(name = "reefDbMeasurementDao")
84      protected ReefDbMeasurementDao measurementDao;
85  
86      @Resource(name = "reefDbPhotoDao")
87      protected ReefDbPhotoDao photoDao;
88  
89      @Resource(name = "reefDbUnitDao")
90      protected ReefDbUnitDao unitDao;
91  
92      @Resource(name = "reefdbDataContext")
93      protected ReefDbDataContext dataContext;
94  
95      @Resource
96      protected ReefDbConfiguration config;
97  
98      private int unitIdMeter;
99  
100     /**
101      * <p>Constructor for ReefDbSamplingOperationDaoImpl.</p>
102      *
103      * @param sessionFactory a {@link org.hibernate.SessionFactory} object.
104      */
105     @Autowired
106     public ReefDbSamplingOperationDaoImpl(SessionFactory sessionFactory) {
107         super(sessionFactory);
108     }
109 
110     @Override
111     public void afterPropertiesSet() {
112         initConstants();
113     }
114 
115     private void initConstants() {
116         unitIdMeter = UnitId.METER.getValue();
117         if (config.isDbCheckConstantsEnable()) {
118             Session session = getSessionFactory().openSession();
119             try {
120                 Assert.notNull(session.get(UnitImpl.class, unitIdMeter));
121             } finally {
122                 fr.ifremer.reefdb.dao.technical.Daos.closeSilently(session);
123             }
124         }
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     public List<SamplingOperationDTO> getSamplingOperationsBySurveyId(int surveyId, boolean withIndividualMeasurements) {
130 
131         Iterator<Object[]> it = queryIterator("samplingOperationsBySurveyId",
132                 "surveyId", IntegerType.INSTANCE, surveyId);
133 
134         List<SamplingOperationDTO> result = Lists.newArrayList();
135 
136         while (it.hasNext()) {
137             Object[] source = it.next();
138             SamplingOperationDTO samplingOperation = toSamplingOperationDTO(Arrays.asList(source).iterator());
139 
140             // add measurements
141             loadMeasurements(samplingOperation, withIndividualMeasurements);
142 
143             result.add(samplingOperation);
144         }
145 
146         return result;
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public void saveSamplingOperationsBySurveyId(int surveyId, Collection<SamplingOperationDTO> samplingOperations) {
152 
153         Survey survey = load(SurveyImpl.class, surveyId);
154         List<Integer> existingSamplingOperationIds = ReefDbBeans.collectProperties(survey.getSamplingOperations(), "samplingOperId");
155 
156         if (CollectionUtils.isNotEmpty(samplingOperations)) {
157             for (SamplingOperationDTO samplingOperation : samplingOperations) {
158                 SamplingOperation target;
159                 if (samplingOperation.getId() == null) {
160                     samplingOperation.setDirty(true);
161                     target = SamplingOperation.Factory.newInstance();
162                 } else {
163                     target = get(samplingOperation.getId());
164                     existingSamplingOperationIds.remove(target.getSamplingOperId());
165 
166                     // check for utFormat change
167                     if (!Objects.equals(target.getSamplingOperUtFormat(), survey.getSurveyUtFormat())) {
168                         samplingOperation.setDirty(true);
169                     }
170 
171                     // check for geometry change (Mantis #46725)
172                     if (!Daos.safeConvertToBoolean(target.getSamplingOperActualPosition())) {
173                         samplingOperation.setDirty(true);
174                     }
175                 }
176 
177                 // save only if dirty
178                 if (samplingOperation.isDirty()) {
179 
180                     beanToEntity(samplingOperation, target, survey);
181 
182                     // set surveyId
183                     target.setSurvey(survey);
184 
185                     getSession().save(target);
186 
187                     // save geometry
188                     saveGeometry(samplingOperation, target, survey);
189 
190                     // update id
191                     samplingOperation.setId(target.getSamplingOperId());
192 
193                     // save measurements
194                     if (samplingOperation.isMeasurementsLoaded()) {
195                         List<MeasurementDTO> allMeasurements = Lists.newArrayList();
196                         allMeasurements.addAll(samplingOperation.getMeasurements());
197                         if (samplingOperation.isIndividualMeasurementsLoaded()) {
198                             allMeasurements.addAll(samplingOperation.getIndividualMeasurements());
199                         }
200                         measurementDao.saveMeasurementsBySamplingOperationId(samplingOperation.getId(), allMeasurements, samplingOperation.isIndividualMeasurementsLoaded());
201                     }
202 
203                     getSession().flush();
204                     getSession().clear();
205                     samplingOperation.setDirty(false);
206                 }
207             }
208         }
209 
210         // remove remaining sampling operations
211         if (!existingSamplingOperationIds.isEmpty()) {
212             for (Integer samplingOperationId : existingSamplingOperationIds) {
213                 remove(samplingOperationId);
214             }
215             getSession().flush();
216             getSession().clear();
217         }
218     }
219 
220     private void loadMeasurements(SamplingOperationDTO samplingOperation, boolean withIndividual) {
221 
222         List<MeasurementDTO> allMeasurements = measurementDao.getMeasurementsBySamplingOperationId(samplingOperation.getId(), withIndividual);
223         if (CollectionUtils.isNotEmpty(allMeasurements)) {
224 
225             // Iterate on all measurement to split them
226             for (MeasurementDTO measurement : allMeasurements) {
227 
228                 // link each measurement to sampling operation
229                 measurement.setSamplingOperation(samplingOperation);
230 
231                 if (measurement.getIndividualId() == null) {
232                     // Add to measurement
233                     samplingOperation.addMeasurements(measurement);
234                 } else if (withIndividual) {
235                     // If measurement has an individualId, split to other list
236                     samplingOperation.addIndividualMeasurements(measurement);
237                 }
238             }
239         }
240 
241         samplingOperation.setMeasurementsLoaded(true);
242         samplingOperation.setIndividualMeasurementsLoaded(withIndividual);
243     }
244 
245     /** {@inheritDoc} */
246     @Override
247     public void removeBySurveyId(int surveyId) {
248 
249         // list all sampling operations delete them unitarily
250         Iterator<Object[]> it = queryIterator("samplingOperationsBySurveyId",
251                 "surveyId", IntegerType.INSTANCE, surveyId);
252 
253         List<Integer> samplingOperationIds = Lists.newArrayList();
254         while (it.hasNext()) {
255             Object[] source = it.next();
256 
257             // read only the Id
258             samplingOperationIds.add((Integer) source[0]);
259         }
260 
261         for (Integer samplingOperationId : samplingOperationIds) {
262             remove(samplingOperationId);
263         }
264     }
265 
266     /** {@inheritDoc} */
267     @Override
268     public void remove(Integer samplingOperationId) {
269 
270         // remove measurement first
271         measurementDao.removeAllMeasurementsBySamplingOperationId(samplingOperationId);
272 
273         // removeMeasurementsByIds photos
274         photoDao.removeBySamplingOperationId(samplingOperationId);
275 
276         super.remove(samplingOperationId);
277     }
278 
279     @Override
280     public int validateBySurveyIds(Collection<Integer> surveyIds, Date validationDate) {
281         return createQuery("validateSamplingOperationBySurveyIds",
282                 "validationDate", DateType.INSTANCE, validationDate)
283                 .setParameterList("surveyIds", surveyIds)
284                 .executeUpdate();
285     }
286 
287     @Override
288     public int unvalidateBySurveyIds(Collection<Integer> surveyIds) {
289         return createQuery("unvalidateSamplingOperationBySurveyIds")
290                 .setParameterList("surveyIds", surveyIds)
291                 .executeUpdate();
292     }
293 
294     @Override
295     public void updateSamplingOperationsControlDate(Collection<Integer> controlledElementsPks, Date controlDate) {
296         createQuery("updateSamplingOperationControlDate")
297                 .setParameterList("operationIds", controlledElementsPks)
298                 .setParameter("controlDate", controlDate).executeUpdate();
299 //        getSession().flush();
300 //        getSession().clear();
301     }
302 
303     // INTERNAL METHODS
304     private SamplingOperationDTO toSamplingOperationDTO(Iterator<Object> it) {
305         SamplingOperationDTO result = ReefDbBeanFactory.newSamplingOperationDTO();
306 
307         result.setId((Integer) it.next());
308         result.setName((String) it.next());
309         result.setTime(Daos.convertToInteger((Number) it.next()));
310         result.setComment((String) it.next());
311         result.setControlDate(Daos.convertToDate(it.next()));
312         result.setSamplingEquipment(samplingEquipmentDao.getSamplingEquipmentById((int) it.next()));
313         result.setSamplingDepartment(departmentDao.getDepartmentById((int) it.next()));
314         result.setSize(Daos.convertToDouble((Float) it.next()));
315 
316         // optional
317         Integer unitId = (Integer) it.next();
318         if (unitId != null) {
319             result.setSizeUnit(unitDao.getUnitById(unitId));
320         }
321         Integer depthLevelId = (Integer) it.next();
322         if (depthLevelId != null) {
323             result.setDepthLevel(referentialDao.getDepthLevelById(depthLevelId));
324         }
325         result.setDepth(Daos.convertToDouble((Float) it.next()));
326         result.setMaxDepth(Daos.convertToDouble((Float) it.next()));
327         result.setMinDepth(Daos.convertToDouble((Float) it.next()));
328         result.setIndividualCount(Daos.convertToInteger((Number) it.next()));
329 
330         // Get positioning system
331         Integer posSystemId = (Integer) it.next();
332 
333         // is actual position ?
334         boolean isActualPosition = Daos.safeConvertToBoolean(it.next(), false);
335 
336         // Geometry and positioning system
337         // -> only keep if actualPosition = true (see mantis #28257)
338         String geometryStr = (String) it.next();
339         if (isActualPosition) {
340             result.setCoordinate(Geometries.getCoordinate(geometryStr));
341 
342             if (posSystemId != null) {
343                 result.setPositioning(referentialDao.getPositioningSystemById(posSystemId));
344             }
345         }
346 
347         return result;
348     }
349 
350     private void beanToEntity(SamplingOperationDTO bean, SamplingOperation entity, Survey survey) {
351 
352         entity.setSamplingOperLb(bean.getName());
353         entity.setSamplingOperTime(bean.getTime());
354         entity.setSamplingOperUtFormat(survey.getSurveyUtFormat());
355         entity.setSamplingOperCm(bean.getComment());
356         entity.setSamplingOperControlDt(bean.getControlDate());
357         entity.setSamplingEquipment(load(SamplingEquipmentImpl.class, bean.getSamplingEquipment().getId()));
358         entity.setDepartment(load(DepartmentImpl.class, bean.getSamplingDepartment().getId()));
359 
360         // Recorder Department (Mantis #42615 Only if REC_DEP_ID is null)
361         if (entity.getRecorderDepartment() == null) {
362             entity.setRecorderDepartment(load(DepartmentImpl.class, dataContext.getRecorderDepartmentId()));
363         }
364 
365         if (entity.getQualityFlag() == null) {
366             entity.setQualityFlag(getDefaultQualityFlag());
367         }
368         if (CollectionUtils.isNotEmpty(survey.getPrograms())) {
369             for (Program program: survey.getPrograms()) {
370                 entity.addPrograms(program);
371             }
372         }
373 
374         entity.setSamplingOperSize(bean.getSize() == null ? null : bean.getSize().floatValue());
375 
376         if (bean.getSizeUnit() == null) {
377             entity.setSizeUnit(null);
378         } else {
379             entity.setSizeUnit(load(UnitImpl.class, bean.getSizeUnit().getId()));
380         }
381 
382         if (bean.getDepthLevel() == null) {
383             entity.setDepthLevel(null);
384         } else {
385             entity.setDepthLevel(load(DepthLevelImpl.class, bean.getDepthLevel().getId()));
386         }
387         entity.setSamplingOperDepth(bean.getDepth() == null ? null : bean.getDepth().floatValue());
388         entity.setSamplingOperMaxDepth(bean.getMaxDepth() == null ? null : bean.getMaxDepth().floatValue());
389         entity.setSamplingOperMinDepth(bean.getMinDepth() == null ? null : bean.getMinDepth().floatValue());
390         // set depth unit if at least one depth not null (Mantis #45752)
391         if (entity.getSamplingOperDepth() != null || entity.getSamplingOperMinDepth() != null || entity.getSamplingOperMaxDepth() != null) {
392             entity.setDepthUnit(load(UnitImpl.class, unitIdMeter));
393         } else {
394             entity.setDepthUnit(null);
395         }
396 
397         entity.setSamplingOperNumberIndiv(bean.getIndividualCount());
398 
399         if (bean.getPositioning() == null) {
400             entity.setPositionningSystem(null);
401         } else {
402             entity.setPositionningSystem(load(PositionningSystemImpl.class, bean.getPositioning().getId()));
403         }
404 
405     }
406 
407     private void saveGeometry(SamplingOperationDTO bean, SamplingOperation entity, Survey survey) {
408 
409         // If coordinates has been filled by user
410         if (Geometries.isValid(bean.getCoordinate())) {
411 
412             if (Geometries.isPoint(bean.getCoordinate())) {
413 
414                 // point
415                 if (entity.getSamplingOperPoints() != null && entity.getSamplingOperPoints().size() == 1) {
416 
417                     SamplingOperPoint pointToUpdate = entity.getSamplingOperPoints().iterator().next();
418                     if (!Geometries.equals(bean.getCoordinate(), pointToUpdate.getSamplingOperPosition())) {
419                         pointToUpdate.setSamplingOperPosition(Geometries.getPointPosition(bean.getCoordinate()));
420                         getSession().update(pointToUpdate);
421                     }
422 
423                 } else {
424                     // create a sampling operation point
425                     SamplingOperPoint point = SamplingOperPoint.Factory.newInstance();
426                     point.setSamplingOperation(entity);
427                     point.setSamplingOperPosition(Geometries.getPointPosition(bean.getCoordinate()));
428                     getSession().save(point);
429                     entity.getSamplingOperPoints().clear();
430                     entity.addSamplingOperPoints(point);
431                 }
432                 entity.getSamplingOperAreas().clear();
433 
434             } else {
435 
436                 // area
437                 if (entity.getSamplingOperAreas() != null && entity.getSamplingOperAreas().size() == 1) {
438 
439                     SamplingOperArea areaToUpdate = entity.getSamplingOperAreas().iterator().next();
440                     if (!Geometries.equals(bean.getCoordinate(), areaToUpdate.getSamplingOperPosition())) {
441                         areaToUpdate.setSamplingOperPosition(Geometries.getAreaPosition(bean.getCoordinate()));
442                         getSession().update(areaToUpdate);
443                     }
444 
445                 } else {
446                     // create a sampling operation area
447                     SamplingOperArea area = SamplingOperArea.Factory.newInstance();
448                     area.setSamplingOperation(entity);
449                     area.setSamplingOperPosition(Geometries.getAreaPosition(bean.getCoordinate()));
450                     getSession().save(area);
451                     entity.getSamplingOperAreas().clear();
452                     entity.addSamplingOperAreas(area);
453                 }
454                 entity.getSamplingOperPoints().clear();
455 
456             }
457 
458             // clear unused coordinates
459             entity.getSamplingOperLines().clear();
460 
461             // Update flag to known is coordinate are filled by user or not (mantis #28257)
462             entity.setSamplingOperActualPosition(fr.ifremer.reefdb.dao.technical.Daos.convertToString(true));
463 
464         } else {
465             saveGeometryFromSurvey(entity, survey);
466         }
467 
468 
469 
470         update(entity);
471 
472     }
473 
474     private void saveGeometryFromSurvey(SamplingOperation entity, Survey survey) {
475 
476         // Point geometry
477         if (CollectionUtils.size(survey.getSurveyPoints()) == 1) {
478             SurveyPoint sourcePoint = CollectionUtils.extractSingleton(survey.getSurveyPoints());
479 
480             // Survey has already a area, so update it
481             if (CollectionUtils.size(entity.getSamplingOperPoints()) == 1) {
482                 SamplingOperPoint targetPoint = CollectionUtils.extractSingleton(entity.getSamplingOperPoints());
483                 if (!Objects.equals(targetPoint.getSamplingOperPosition(), sourcePoint.getSurveyPosition())) {
484                     targetPoint.setSamplingOperPosition(sourcePoint.getSurveyPosition());
485                     getSession().update(targetPoint);
486                 }
487             }
488 
489             // No existing area: create new
490             else {
491                 SamplingOperPoint targetPoint = SamplingOperPoint.Factory.newInstance();
492                 targetPoint.setSamplingOperation(entity);
493                 targetPoint.setSamplingOperPosition(sourcePoint.getSurveyPosition());
494                 getSession().save(targetPoint);
495                 entity.getSamplingOperPoints().clear();
496                 entity.addSamplingOperPoints(targetPoint);
497             }
498 
499             // Clean unused
500             entity.getSamplingOperLines().clear();
501             entity.getSamplingOperAreas().clear();
502         }
503 
504         // Line geometry
505         else if (CollectionUtils.size(survey.getSurveyLines()) == 1) {
506             SurveyLine sourceLine = CollectionUtils.extractSingleton(survey.getSurveyLines());
507 
508             // Survey has already a area, so update it
509             if (CollectionUtils.size(entity.getSamplingOperLines()) == 1) {
510                 SamplingOperLine targetLine = CollectionUtils.extractSingleton(entity.getSamplingOperLines());
511                 if (!Objects.equals(sourceLine.getSurveyPosition(), targetLine.getSamplingOperPosition())) {
512                     targetLine.setSamplingOperPosition(sourceLine.getSurveyPosition());
513                     getSession().update(targetLine);
514                 }
515             }
516 
517             // No existing area: create new
518             else {
519                 SamplingOperLine targetLine = SamplingOperLine.Factory.newInstance();
520                 targetLine.setSamplingOperation(entity);
521                 targetLine.setSamplingOperPosition(sourceLine.getSurveyPosition());
522                 getSession().save(targetLine);
523                 entity.getSamplingOperLines().clear();
524                 entity.addSamplingOperLines(targetLine);
525             }
526 
527             // Clean unused
528             entity.getSamplingOperPoints().clear();
529             entity.getSamplingOperAreas().clear();
530         }
531 
532         // Area geometry
533         else if (CollectionUtils.size(survey.getSurveyAreas()) == 1) {
534             SurveyArea sourceArea = CollectionUtils.extractSingleton(survey.getSurveyAreas());
535 
536             // Survey has already a area, so update it
537             if (CollectionUtils.size(entity.getSamplingOperAreas()) == 1) {
538                 SamplingOperArea targetArea = CollectionUtils.extractSingleton(entity.getSamplingOperAreas());
539                 if (!Objects.equals(sourceArea.getSurveyPosition(), targetArea.getSamplingOperPosition())) {
540                     targetArea.setSamplingOperPosition(sourceArea.getSurveyPosition());
541                     getSession().update(targetArea);
542                 }
543             }
544 
545             // No existing area: create new
546             else {
547                 SamplingOperArea targetArea = SamplingOperArea.Factory.newInstance();
548                 targetArea.setSamplingOperation(entity);
549                 targetArea.setSamplingOperPosition(sourceArea.getSurveyPosition());
550                 getSession().save(targetArea);
551                 entity.getSamplingOperAreas().clear();
552                 entity.addSamplingOperAreas(targetArea);
553             }
554 
555             // Clean unused
556             entity.getSamplingOperPoints().clear();
557             entity.getSamplingOperLines().clear();
558         }
559         else {
560             throw new DataIntegrityViolationException(String.format("Could not found geometry on survey [surveyId=%s].", survey.getSurveyId()));
561         }
562 
563         // Update flag to known is coordinate is not filled by user or not (mantis #28257)
564         entity.setSamplingOperActualPosition(fr.ifremer.reefdb.dao.technical.Daos.convertToString(false));
565 
566         // Apply positioning system from survey (see mantis #28706)
567         entity.setPositionningSystem(survey.getPositionningSystem());
568     }
569 
570     /**
571      * return the default quality flag
572      *
573      * @return the default quality flag
574      */
575     private QualityFlag getDefaultQualityFlag() {
576         return load(QualityFlagImpl.class, QualityFlagCode.NOT_QUALIFIED.getValue()); // = non qualifié
577     }
578 
579 }