View Javadoc
1   package fr.ifremer.dali.dao.data.photo;
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.Lists;
27  import fr.ifremer.dali.config.DaliConfiguration;
28  import fr.ifremer.dali.dao.referential.DaliReferentialDao;
29  import fr.ifremer.dali.dao.technical.Daos;
30  import fr.ifremer.dali.dto.DaliBeanFactory;
31  import fr.ifremer.dali.dto.DaliBeans;
32  import fr.ifremer.dali.dto.data.photo.PhotoDTO;
33  import fr.ifremer.dali.dto.data.sampling.SamplingOperationDTO;
34  import fr.ifremer.dali.service.DaliDataContext;
35  import fr.ifremer.dali.service.DaliTechnicalException;
36  import fr.ifremer.quadrige3.core.dao.administration.user.DepartmentImpl;
37  import fr.ifremer.quadrige3.core.dao.data.photo.Photo;
38  import fr.ifremer.quadrige3.core.dao.data.photo.PhotoDaoImpl;
39  import fr.ifremer.quadrige3.core.dao.data.samplingoperation.SamplingOperationImpl;
40  import fr.ifremer.quadrige3.core.dao.data.survey.Survey;
41  import fr.ifremer.quadrige3.core.dao.data.survey.SurveyImpl;
42  import fr.ifremer.quadrige3.core.dao.referential.*;
43  import fr.ifremer.quadrige3.core.dao.technical.Assert;
44  import fr.ifremer.quadrige3.core.dao.technical.Images;
45  import org.apache.commons.collections4.CollectionUtils;
46  import org.apache.commons.io.FileUtils;
47  import org.apache.commons.lang3.StringUtils;
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.springframework.beans.factory.annotation.Autowired;
53  import org.springframework.stereotype.Repository;
54  
55  import javax.annotation.Resource;
56  import java.io.File;
57  import java.io.IOException;
58  import java.util.*;
59  
60  /**
61   * <p>DaliPhotoDaoImpl class.</p>
62   *
63   * @author Ludovic
64   */
65  @Repository("daliPhotoDao")
66  public class DaliPhotoDaoImpl extends PhotoDaoImpl implements DaliPhotoDao {
67  
68      @Autowired
69      protected DaliConfiguration config;
70  
71      @Resource(name = "daliReferentialDao")
72      private DaliReferentialDao referentialDao;
73  
74      @Resource(name = "daliDataContext")
75      private DaliDataContext dataContext;
76  
77      /**
78       * <p>Constructor for DaliPhotoDaoImpl.</p>
79       *
80       * @param sessionFactory a {@link org.hibernate.SessionFactory} object.
81       */
82      @Autowired
83      public DaliPhotoDaoImpl(SessionFactory sessionFactory) {
84          super(sessionFactory);
85      }
86  
87      /**
88       * {@inheritDoc}
89       */
90      @Override
91      public List<PhotoDTO> getPhotosBySurveyId(int surveyId) {
92  
93          Iterator<Object[]> it = queryIterator("photosBySurveyId",
94                  "surveyObjectTypeCode", StringType.INSTANCE, Daos.SURVEY_OBJECT_TYPE,
95                  "samplingOperationObjectTypeCode", StringType.INSTANCE, Daos.SAMPLING_OPERATION_OBJECT_TYPE,
96                  "surveyId", IntegerType.INSTANCE, surveyId);
97  
98          List<PhotoDTO> result = Lists.newArrayList();
99          while (it.hasNext()) {
100             Object[] row = it.next();
101             result.add(toPhotoDTO(Arrays.asList(row).iterator()));
102         }
103         return result;
104     }
105 
106     /**
107      * {@inheritDoc}
108      */
109     @Override
110     public void savePhotosBySurveyId(int surveyId, Collection<PhotoDTO> photos) {
111 
112         Survey survey = get(SurveyImpl.class, surveyId);
113 
114         List<Integer> existingPhotosIds = DaliBeans.collectIds(getPhotosBySurveyId(surveyId));
115 
116         if (photos != null) {
117             for (PhotoDTO source : photos) {
118 
119                 // remove from existing
120                 if (source.getId() != null) {
121                     existingPhotosIds.remove(source.getId());
122                 }
123 
124                 // save if dirty
125                 if (source.isDirty()) {
126                     savePhotoInSurvey(source, survey);
127                     source.setDirty(false);
128                 }
129 
130             }
131         }
132 
133         // remove the not saved
134         if (CollectionUtils.isNotEmpty(existingPhotosIds)) {
135             for (Integer idToRemove : existingPhotosIds) {
136                 remove(idToRemove);
137             }
138         }
139     }
140 
141     private void savePhotoInSurvey(PhotoDTO photo, Survey survey) {
142 
143         Photo target;
144         if (photo.getId() == null) {
145             target = Photo.Factory.newInstance();
146         } else {
147             target = get(photo.getId());
148         }
149 
150         // mandatory fields
151         target.setSurvey(survey);
152         if (photo.getSamplingOperation() != null) {
153             // link the photo to the sampling operation
154             target.setObjectType(load(ObjectTypeImpl.class, Daos.SAMPLING_OPERATION_OBJECT_TYPE));
155             target.setObjectId(photo.getSamplingOperation().getId());
156             target.setSamplingOperation(load(SamplingOperationImpl.class, photo.getSamplingOperation().getId()));
157         } else {
158             // if no sampling operation provided, link the photo to the survey
159             target.setObjectType(load(ObjectTypeImpl.class, Daos.SURVEY_OBJECT_TYPE));
160             target.setObjectId(survey.getSurveyId());
161         }
162 
163         // Recorder Department (Mantis #42614 Only if REC_DEP_ID is null)
164         if (target.getRecorderDepartment() == null) {
165             target.setRecorderDepartment(load(DepartmentImpl.class, dataContext.getRecorderDepartmentId()));
166         }
167 
168         // optional fields
169         target.setPhotoNm(photo.getName());
170         if (photo.getPhotoType() != null) {
171             target.setPhotoType(load(PhotoTypeImpl.class, photo.getPhotoType().getCode())); // use this String as photo type waiting for PhotoTypeDTO
172         } else {
173             target.setPhotoType(null);
174         }
175         target.setPhotoCm(photo.getCaption());
176         target.setPhotoDt(photo.getDate());
177         target.setPhotoDirDc(photo.getDirection());
178         target.setQualityFlag(getDefaultQualityFlag());
179 
180         // save now to obtain new id
181         getSession().save(target);
182         photo.setId(target.getPhotoId());
183 
184         // compute target file name
185         String targetPath = Daos.computePhotoFilePath(photo, target);
186 
187         if (!targetPath.equals(photo.getPath())) {
188 
189             // save case :
190             // 1 - the photo is just imported : path == null and fullPath points to tempDir
191             // 2 - the photo has been associated to another parent : path == old path where the file should be
192 
193             File sourceFile = photo.getPath() == null
194                     ? new File(photo.getFullPath())
195                     : new File(config.getDbPhotoDirectory(), photo.getPath());
196 
197             Assert.isTrue(sourceFile.exists(), "photo not found : " + sourceFile);
198             File targetFile = new File(config.getDbPhotoDirectory(), targetPath);
199 
200             try {
201                 // move main image
202                 FileUtils.moveFile(sourceFile, targetFile);
203 
204                 // try find other images
205                 File mediumSourceFile = Images.getMediumImageFile(sourceFile);
206                 if (mediumSourceFile.exists()) {
207                     File mediumTargetFile = Images.getMediumImageFile(targetFile);
208                     FileUtils.moveFile(mediumSourceFile, mediumTargetFile);
209                 }
210                 File smallSourceFile = Images.getSmallImageFile(sourceFile);
211                 if (smallSourceFile.exists()) {
212                     File smallTargetFile = Images.getSmallImageFile(targetFile);
213                     FileUtils.moveFile(smallSourceFile, smallTargetFile);
214                 }
215 
216             } catch (IOException ex) {
217                 throw new DaliTechnicalException(ex);
218             }
219 
220             // update bean
221             photo.setPath(targetPath);
222             photo.setFullPath(targetFile.getAbsolutePath());
223         }
224 
225         // update photo link if differs
226         if (!targetPath.equals(target.getPhotoLk())) {
227 
228             target.setPhotoLk(targetPath);
229             update(target);
230         }
231     }
232 
233     /**
234      * {@inheritDoc}
235      */
236     @Override
237     public void remove(Integer photoId) {
238         // delete file
239         String fileName = get(photoId).getPhotoLk();
240         if (StringUtils.isNotBlank(fileName)) {
241             Images.deleteImage(new File(config.getDbPhotoDirectory(), fileName));
242         }
243 
244         // then remove entity
245         super.remove(photoId);
246     }
247 
248     /**
249      * {@inheritDoc}
250      */
251     @Override
252     public void removeBySurveyId(int surveyId) {
253         Iterator<Integer> it = queryIteratorTyped("photoIdsBySurveyId",
254                 "surveyObjectTypeCode", StringType.INSTANCE, Daos.SURVEY_OBJECT_TYPE,
255                 "samplingOperationObjectTypeCode", StringType.INSTANCE, Daos.SAMPLING_OPERATION_OBJECT_TYPE,
256                 "surveyId", IntegerType.INSTANCE, surveyId);
257 
258         while (it.hasNext()) {
259             remove(it.next());
260         }
261     }
262 
263     /**
264      * {@inheritDoc}
265      */
266     @Override
267     public void removeBySamplingOperationId(int samplingOperationId) {
268         Iterator<Integer> it = queryIteratorTyped("photoIdsBySamplingOperationId",
269                 "samplingOperationObjectTypeCode", StringType.INSTANCE, Daos.SAMPLING_OPERATION_OBJECT_TYPE,
270                 "samplingOperationId", IntegerType.INSTANCE, samplingOperationId);
271 
272         while (it.hasNext()) {
273             remove(it.next());
274         }
275     }
276 
277     @Override
278     public int validateBySurveyIds(Collection<Integer> surveyIds, Date validationDate) {
279         return createQuery("validatePhotosBySurveyIds",
280                 "surveyObjectTypeCode", StringType.INSTANCE, Daos.SURVEY_OBJECT_TYPE,
281                 "samplingOperationObjectTypeCode", StringType.INSTANCE, Daos.SAMPLING_OPERATION_OBJECT_TYPE,
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("unvalidatePhotosBySurveyIds",
290                 "surveyObjectTypeCode", StringType.INSTANCE, Daos.SURVEY_OBJECT_TYPE,
291                 "samplingOperationObjectTypeCode", StringType.INSTANCE, Daos.SAMPLING_OPERATION_OBJECT_TYPE)
292                 .setParameterList("surveyIds", surveyIds)
293                 .executeUpdate();
294     }
295 
296     @Override
297     public int qualifyBySurveyIds(List<Integer> surveyIds, Date qualificationDate) {
298         return createQuery("qualifyPhotosBySurveyIds",
299                 "surveyObjectTypeCode", StringType.INSTANCE, Daos.SURVEY_OBJECT_TYPE,
300                 "samplingOperationObjectTypeCode", StringType.INSTANCE, Daos.SAMPLING_OPERATION_OBJECT_TYPE,
301                 "qualificationDate", DateType.INSTANCE, qualificationDate)
302                 .setParameterList("surveyIds", surveyIds)
303                 .executeUpdate();
304     }
305 
306     /**
307      * return the default quality flag
308      */
309     private QualityFlag getDefaultQualityFlag() {
310         return load(QualityFlagImpl.class, QualityFlagCode.NOT_QUALIFIED.getValue()); // = non qualifié
311     }
312 
313     private PhotoDTO toPhotoDTO(Iterator<Object> it) {
314         PhotoDTO result = DaliBeanFactory.newPhotoDTO();
315         result.setId((Integer) it.next());
316         String objectTypeCode = (String) it.next();
317         Integer objectId = (Integer) it.next();
318         if (Daos.SAMPLING_OPERATION_OBJECT_TYPE.equals(objectTypeCode)) {
319             // set a dummy sampling operation
320             // TODO full object should be set in service
321             SamplingOperationDTO dummySamplingOperation = DaliBeanFactory.newSamplingOperationDTO();
322             dummySamplingOperation.setId(objectId);
323             result.setSamplingOperation(dummySamplingOperation);
324         }
325         result.setName((String) it.next());
326         result.setCaption((String) it.next());
327         result.setDate(Daos.convertToDate(it.next()));
328         result.setDirection((String) it.next());
329         result.setPath((String) it.next());
330         File fullPath = new File(config.getDbPhotoDirectory(), result.getPath());
331         result.setFullPath(fullPath.getPath());
332 
333         String photoTypeCode = (String) it.next();
334         if (StringUtils.isNotBlank(photoTypeCode)) {
335             result.setPhotoType(referentialDao.getPhotoTypeByCode(photoTypeCode));
336         }
337 
338         // remote id for download purpose
339         result.setRemoteId((Integer) it.next());
340 
341         return result;
342     }
343 
344 }