View Javadoc
1   package fr.ifremer.quadrige3.synchro.intercept.data.attachement;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Synchro
6    * %%
7    * Copyright (C) 2017 - 2019 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Affero General Public License as published by
11   * the Free Software Foundation, either version 3 of the License, or
12   * (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 Affero General Public License
20   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21   * #L%
22   */
23  
24  import com.google.common.collect.ImmutableSet;
25  import com.google.common.collect.Lists;
26  import com.google.common.eventbus.Subscribe;
27  import fr.ifremer.common.synchro.SynchroTechnicalException;
28  import fr.ifremer.common.synchro.dao.SynchroBaseDao;
29  import fr.ifremer.common.synchro.dao.SynchroTableDao;
30  import fr.ifremer.common.synchro.intercept.SynchroInterceptorBase;
31  import fr.ifremer.common.synchro.intercept.SynchroOperationRepository;
32  import fr.ifremer.common.synchro.meta.SynchroDatabaseMetadata;
33  import fr.ifremer.common.synchro.meta.SynchroJoinMetadata;
34  import fr.ifremer.common.synchro.meta.SynchroTableMetadata;
35  import fr.ifremer.common.synchro.meta.event.LoadJoinEvent;
36  import fr.ifremer.common.synchro.meta.event.LoadTableEvent;
37  import fr.ifremer.common.synchro.service.SynchroResult;
38  import fr.ifremer.common.synchro.service.SynchroTableOperation;
39  import fr.ifremer.common.synchro.util.file.FileOperation;
40  import fr.ifremer.common.synchro.util.file.FileOperationBuilder;
41  import fr.ifremer.common.synchro.util.file.impl.BasicFileOperation;
42  import fr.ifremer.quadrige3.core.dao.referential.ObjectTypeCode;
43  import fr.ifremer.quadrige3.core.dao.technical.Assert;
44  import fr.ifremer.quadrige3.core.dao.technical.Daos;
45  import fr.ifremer.quadrige3.core.dao.technical.Images;
46  import fr.ifremer.quadrige3.core.exception.QuadrigeTechnicalException;
47  import fr.ifremer.quadrige3.synchro.intercept.data.AbstractDataInterceptor;
48  import fr.ifremer.quadrige3.synchro.meta.DatabaseColumns;
49  import fr.ifremer.quadrige3.synchro.meta.data.DataSynchroTables;
50  import fr.ifremer.quadrige3.synchro.service.SynchroDirection;
51  import fr.ifremer.quadrige3.synchro.service.data.DataSynchroContext;
52  import org.apache.commons.io.FileUtils;
53  import org.apache.commons.io.FilenameUtils;
54  import org.apache.commons.logging.Log;
55  import org.apache.commons.logging.LogFactory;
56  import org.hibernate.tool.hbm2ddl.TableMetadata;
57  
58  import java.io.File;
59  import java.io.IOException;
60  import java.sql.PreparedStatement;
61  import java.sql.ResultSet;
62  import java.sql.SQLException;
63  import java.sql.Timestamp;
64  import java.util.ArrayList;
65  import java.util.LinkedHashMap;
66  import java.util.List;
67  import java.util.Map;
68  
69  /**
70   * @author peck7 on 11/06/2019.
71   */
72  public class PhotoInterceptor extends AbstractDataInterceptor {
73  
74      private static final Log LOG = LogFactory.getLog(PhotoInterceptor.class);
75  
76      private int photoIdIndex = -1;
77      private int surveyIdIndex = -1;
78      private int samplingOperIdIndex = -1;
79      private int sampleIdIndex = -1;
80      private int objectIdIndex = -1;
81      private int objectTypeCdIndex = -1;
82      private int updateDateIndex = -1;
83      private int pathIndex = -1;
84      private int remoteIdIndex = -1;
85  
86      private PreparedStatement selectRemoteIdAndParentIdsFromSampleIdStatement = null;
87      private String selectRemoteIdAndParentIdsFromSampleIdQuery;
88      private PreparedStatement selectParentIdFromSamplingOperIdStatement = null;
89      private String selectRemoteIdAndParentIdFromSamplingOperIdQuery;
90      private String selectRemoteIdBySurveyIdQuery;
91  
92      private String selectLocalIdBySampleIdQuery;
93      private String selectLocalIdBySamplingOperIdQuery;
94      private String selectLocalIdBySurveyIdQuery;
95  
96      private File sourceDirectory = null;
97      private File targetDirectory = null;
98  
99      public PhotoInterceptor() {
100         super();
101         this.selectRemoteIdAndParentIdsFromSampleIdQuery = initSelectRemoteIdAndParentIdFromSampleIdQuery();
102         this.selectRemoteIdAndParentIdFromSamplingOperIdQuery = initSelectRemoteIdAndParentIdFromSamplingOperIdQuery();
103         this.selectRemoteIdBySurveyIdQuery = initSelectRemoteIdFromSurveyId();
104         this.selectLocalIdBySurveyIdQuery = initSelectLocalIdFromSurveyId();
105         this.selectLocalIdBySamplingOperIdQuery = initSelectLocalIdFromSamplingOperId();
106         this.selectLocalIdBySampleIdQuery = initSelectLocalIdFromSampleId();
107 
108         setEnableOnWrite(true);
109     }
110 
111     @Override
112     public boolean doApply(SynchroDatabaseMetadata meta, TableMetadata table) {
113         return table.getName().equalsIgnoreCase(DataSynchroTables.PHOTO.name());
114     }
115 
116     @Override
117     public SynchroInterceptorBase clone() {
118         PhotoInterceptor newBean = (PhotoInterceptor) super.clone();
119         newBean.selectRemoteIdAndParentIdFromSamplingOperIdQuery = this.selectRemoteIdAndParentIdFromSamplingOperIdQuery;
120         newBean.selectRemoteIdAndParentIdsFromSampleIdQuery = this.selectRemoteIdAndParentIdsFromSampleIdQuery;
121         newBean.selectRemoteIdBySurveyIdQuery = this.selectRemoteIdBySurveyIdQuery;
122         newBean.selectLocalIdBySampleIdQuery = this.selectLocalIdBySampleIdQuery;
123         newBean.selectLocalIdBySamplingOperIdQuery = this.selectLocalIdBySamplingOperIdQuery;
124         newBean.selectLocalIdBySurveyIdQuery = this.selectLocalIdBySurveyIdQuery;
125 
126         newBean.photoIdIndex = this.photoIdIndex;
127         newBean.surveyIdIndex = this.surveyIdIndex;
128         newBean.samplingOperIdIndex = this.samplingOperIdIndex;
129         newBean.sampleIdIndex = this.sampleIdIndex;
130         newBean.objectIdIndex = this.objectIdIndex;
131         newBean.objectTypeCdIndex = this.objectTypeCdIndex;
132         newBean.updateDateIndex = this.updateDateIndex;
133         newBean.pathIndex = this.pathIndex;
134         newBean.remoteIdIndex = this.remoteIdIndex;
135         return newBean;
136     }
137 
138     @Override
139     protected void doClose() throws IOException {
140         super.doClose();
141 
142         sourceDirectory = null;
143         targetDirectory = null;
144     }
145 
146     /**
147      * <p>
148      * handleJoinLoad.
149      * </p>
150      *
151      * @param e a {@link fr.ifremer.common.synchro.meta.event.LoadJoinEvent} object.
152      */
153     @Subscribe
154     public void handleJoinLoad(LoadJoinEvent e) {
155         SynchroJoinMetadata join = e.join;
156         // Do not apply if mirror database
157         if (!join.isValid()) {
158             return;
159         }
160 
161         SynchroTableMetadata pkTable = join.getPkTable();
162         String pkTableName = pkTable.getName();
163         SynchroDirection direction = getConfig().getDirection();
164 
165         // IMPORT: Server DB -> Temp DB
166         if (direction == SynchroDirection.IMPORT_SERVER2TEMP) {
167 
168             // Only keep link to SURVEY (survey_id)
169             if (DataSynchroTables.SAMPLING_OPERATION.name().equalsIgnoreCase(pkTableName)
170                     || DataSynchroTables.SAMPLE.name().equalsIgnoreCase(pkTableName)) {
171 
172                 join.setIsValid(false);
173             }
174         }
175     }
176 
177     /**
178      * <p>
179      * handleTableLoad.
180      * </p>
181      *
182      * @param e a {@link fr.ifremer.common.synchro.meta.event.LoadTableEvent} object.
183      */
184     @Subscribe
185     public void handleTableLoad(LoadTableEvent e) {
186         SynchroTableMetadata table = e.table;
187 
188         photoIdIndex = table.getSelectColumnIndex(DatabaseColumns.PHOTO_ID.name());
189         surveyIdIndex = table.getSelectColumnIndex(DatabaseColumns.SURVEY_ID.name());
190         samplingOperIdIndex = table.getSelectColumnIndex(DatabaseColumns.SAMPLING_OPER_ID.name());
191         sampleIdIndex = table.getSelectColumnIndex(DatabaseColumns.SAMPLE_ID.name());
192         objectIdIndex = table.getSelectColumnIndex(DatabaseColumns.OBJECT_ID.name());
193         objectTypeCdIndex = table.getSelectColumnIndex(DatabaseColumns.OBJECT_TYPE_CD.name());
194         updateDateIndex = table.getSelectColumnIndex(getConfig().getColumnUpdateDate());
195         remoteIdIndex = table.getSelectColumnIndex(getConfig().getColumnRemoteId());
196         pathIndex = table.getSelectColumnIndex(DatabaseColumns.PHOTO_LK.name());
197 
198         // EXPORT: Temp DB -> Server DB
199         if (getConfig().getDirection() == SynchroDirection.EXPORT_TEMP2SERVER) {
200 
201             // When select by SURVEY_ID, some other ID should be NULL
202             table.addSelectByFksWhereClause(DatabaseColumns.SURVEY_ID.name(),
203                     String.format("t.%s IS NULL AND t.%s IS NULL",
204                             DatabaseColumns.SAMPLING_OPER_ID.name(),
205                             DatabaseColumns.SAMPLE_ID.name()));
206 
207             // When select by SAMPLING_OPER_ID, SAMPLE_ID should be NULL
208             table.addSelectByFksWhereClause(DatabaseColumns.SAMPLING_OPER_ID.name(),
209                     String.format("t.%s IS NULL",
210                             DatabaseColumns.SAMPLE_ID.name()));
211         }
212     }
213 
214     @Override
215     protected void doOnWrite(Object[] data, List<Object> pk, SynchroTableDao sourceDao, SynchroTableDao targetDao, SynchroOperationRepository buffer, boolean insert) throws SQLException {
216 
217         if (buffer == null) return;
218 
219         SynchroDirection direction = getConfig().getDirection();
220         DataSynchroContext context = (DataSynchroContext) buffer.getSynchroContext();
221         SynchroResult result = context.getResult();
222 
223         // IMPORT: Server DB -> Temp DB
224         if (direction == SynchroDirection.IMPORT_SERVER2TEMP) {
225             // delete surveyId if samplingOperId is set
226             if (data[samplingOperIdIndex] != null) {
227                 data[surveyIdIndex] = null;
228             }
229 
230             // delete samplingOperId if sampleId is set
231             if (data[sampleIdIndex] != null) {
232                 data[samplingOperIdIndex] = null;
233                 data[surveyIdIndex] = null;
234             }
235 
236             // Get source update date
237             Timestamp updateDate = (Timestamp) data[updateDateIndex];
238 
239             // Get last synchronization date
240             Timestamp lastSynchronizationDate = context.getLastSynchronizationDate();
241 
242             int updateDateCompare = fr.ifremer.common.synchro.dao.Daos.compareUpdateDates(updateDate, lastSynchronizationDate);
243             if (updateDateCompare > 0) {
244 
245                 // Copy file only if update date is after last synchro date
246                 String path = String.valueOf(data[pathIndex]);
247                 // Add copy operation but don't throw exception if file is missing (Mantis #47989)
248                 addCopyOperation(path, path, context, result, buffer, false);
249             }
250 
251         }
252 
253         // IMPORT: Temp DB -> Local DB
254         else if (direction == SynchroDirection.IMPORT_TEMP2LOCAL) {
255 
256             Number remoteObjectId = (Number) data[objectIdIndex];
257             String objectTypeCode = String.valueOf(data[objectTypeCdIndex]);
258             String remotePath = String.valueOf(data[pathIndex]);
259 
260             // Override OBJECT_ID column
261             Number localObjectId = null;
262             if (data[sampleIdIndex] != null) {
263                 localObjectId = getLocalIdFromSampleId(targetDao, Long.parseLong(data[sampleIdIndex].toString()));
264             } else if (data[samplingOperIdIndex] != null) {
265                 localObjectId = getLocalIdFromSamplingOperId(targetDao, Long.parseLong(data[samplingOperIdIndex].toString()));
266             } else if (data[surveyIdIndex] != null) {
267                 localObjectId = getLocalIdFromSurveyId(targetDao, Long.parseLong(data[surveyIdIndex].toString()));
268             }
269             if (localObjectId == null) {
270                 throw new SynchroTechnicalException("The local Id is not found for the object " + objectTypeCode + " remoteId=" + remoteObjectId);
271             }
272             data[objectIdIndex] = localObjectId;
273 
274             // Override PATH column
275             String localPath = Daos.computePhotoFilePath(objectTypeCode, localObjectId, (Number) pk.get(0), FilenameUtils.getExtension(remotePath));
276             data[pathIndex] = localPath;
277 
278             // Copy file
279             addCopyOperation(remotePath, localPath, context, result, buffer, false);
280 
281         }
282 
283         // IMPORT: File DB -> Local DB
284         else if (direction == SynchroDirection.IMPORT_FILE2LOCAL) {
285 
286         }
287 
288         // EXPORT: Local DB -> Temp DB
289         else if (direction == SynchroDirection.EXPORT_LOCAL2TEMP) {
290 
291             // Get actual remote id
292             Object remoteObjectId = data[remoteIdIndex];
293             if (remoteObjectId == null && insert) {
294 
295                 // Copy file to temp only if not already synchronized
296                 String path = String.valueOf(data[pathIndex]);
297                 addCopyOperation(path, path, context, result, buffer, true);
298             }
299 
300         }
301 
302         // EXPORT: Temp DB -> Server DB
303         else if (direction == SynchroDirection.EXPORT_TEMP2SERVER) {
304 
305             String objectTypeCode = String.valueOf(data[objectTypeCdIndex]);
306             String localPath = String.valueOf(data[pathIndex]);
307 
308             // Make sure the objectId is rewrite with remote identifier
309             Number remoteObjectId;
310 
311             // If parent object is a sample
312             if (data[sampleIdIndex] != null) {
313                 Number[] ids = getRemoteIdAndParentIdFromSampleId(sourceDao, Long.parseLong(data[sampleIdIndex].toString()));
314                 remoteObjectId = ids[0];
315                 data[surveyIdIndex] = ids[1];
316                 data[samplingOperIdIndex] = ids[2];
317             }
318 
319             // If parent object is a sampling operation
320             else if (data[samplingOperIdIndex] != null) {
321                 Number[] ids = getRemoteIdAndParentIdFromSamplingOperId(sourceDao, Long.parseLong(data[samplingOperIdIndex].toString()));
322                 remoteObjectId = ids[0];
323                 data[surveyIdIndex] = ids[1];
324             }
325 
326             // If parent is survey
327             else if (data[surveyIdIndex] != null) {
328                 remoteObjectId = getRemoteIdFromSurveyId(sourceDao, Long.parseLong(data[surveyIdIndex].toString()));
329             }
330 
331             // Else (should never append)
332             else {
333                 throw new QuadrigeTechnicalException("Photo found, without any parent filled. This should never append.");
334             }
335 
336             data[objectIdIndex] = remoteObjectId;
337 
338             // Override PATH column
339             String remotePath = Daos.computePhotoFilePath(objectTypeCode, remoteObjectId, (Number) pk.get(0), FilenameUtils.getExtension(localPath));
340             data[pathIndex] = remotePath;
341 
342             // Copy file
343             boolean copy = addCopyOperation(localPath, remotePath, context, result, buffer, false);
344 
345             if (!copy) {
346                 // If file is not copied, means that the file is already synchronized, preserve update_date on server
347                 buffer.addMissingColumnUpdate(getConfig().getColumnUpdateDate(), pk, data[updateDateIndex]);
348             }
349 
350         }
351 
352         Object photoId = data[photoIdIndex];
353         if (photoId != null) {
354             buffer.addChildToUpdateFromManyColumns(DataSynchroTables.QUALIFICATION_HISTORY.name(),
355                 ImmutableSet.of(DatabaseColumns.OBJECT_TYPE_CD.name(), DatabaseColumns.QUAL_HIST_ELEMENT_ID.name()),
356                 Lists.newArrayList(ObjectTypeCode.PHOTO.value(), Long.parseLong(photoId.toString())));
357         }
358     }
359 
360     @Override
361     protected void doOnDelete(List<Object> pk, SynchroTableDao sourceDao, SynchroTableDao targetDao, SynchroOperationRepository buffer) throws SQLException {
362 
363         if (buffer == null)
364             return;
365 
366         SynchroResult result = buffer.getSynchroContext().getResult();
367         DataSynchroContext context = (DataSynchroContext) buffer.getSynchroContext();
368 
369         // Disable photo deletion if file synchro (Mantis #49959)
370         if (context.getDirection() == SynchroDirection.IMPORT_FILE2LOCAL || context.getDirection() == SynchroDirection.EXPORT_LOCAL2FILE)
371             return;
372 
373         Object id = pk.get(0);
374         String query = String.format("SELECT %s FROM %s WHERE %s=?",
375                 DatabaseColumns.PHOTO_LK.name(),
376                 DataSynchroTables.PHOTO.name(),
377                 DatabaseColumns.PHOTO_ID.name()
378         );
379         String path = targetDao.getUniqueTyped(query, new Object[]{id});
380 
381         // Do the file deletion
382         addDeleteOperation(path, context, result, buffer);
383 
384     }
385 
386     private boolean addCopyOperation(String srcPath, String destPath,
387                                      DataSynchroContext context,
388                                      SynchroResult result,
389                                      SynchroOperationRepository buffer,
390                                      boolean throwExceptionIfScrNotFound) {
391 
392         if (!getConfig().isEnablePhoto()) {
393             // Skip copy operation
394             return false;
395         }
396 
397         Map<File, File> fileCopyMap = new LinkedHashMap<>();
398         {
399             // Get source photo
400             File src = new File(getSourceDirectory(context), srcPath);
401             if (!src.exists()) {
402                 if (throwExceptionIfScrNotFound) {
403                     throw new SynchroTechnicalException("Unable to locate source file: " + src.getPath());
404                 }
405                 return false;
406             }
407 
408             // Get destination photo
409             File dest = new File(getTargetDirectory(context), destPath);
410 
411             if (src.equals(dest)) {
412                 throw new SynchroTechnicalException("Source and destination are the same, please set photo directory correctly");
413             }
414 
415             fileCopyMap.put(src, dest);
416 
417             // Get other photos
418             File mediumSrc = Images.getMediumImageFile(src);
419             if (mediumSrc.exists()) {
420                 fileCopyMap.put(mediumSrc, Images.getMediumImageFile(dest));
421             }
422             File smallSrc = Images.getSmallImageFile(src);
423             if (smallSrc.exists()) {
424                 fileCopyMap.put(smallSrc, Images.getSmallImageFile(dest));
425             }
426         }
427 
428         for (File src : fileCopyMap.keySet()) {
429             File dest = null;
430             try {
431                 dest = fileCopyMap.get(src);
432                 Assert.notNull(dest);
433 
434                 if (LOG.isDebugEnabled()) {
435                     LOG.debug(String.format("[%s] preparing copy [%s] -> [%s]",
436                             DataSynchroTables.PHOTO.name(),
437                             srcPath,
438                             destPath));
439                 }
440 
441                 FileOperation copy;
442                 // If target = TempDB: no lock and undo
443                 if (context.getTarget().isMirrorDatabase()) {
444                     copy = FileOperationBuilder.prepareCopy(src, dest)
445                             .build();
446                 }
447                 // If target DB is not TempDB: apply lock and undo
448                 else {
449                     copy = FileOperationBuilder.prepareCopy(src, dest)
450                             .withLock()
451                             .withUndo()
452                             .build();
453                 }
454                 buffer.addFileOperation(copy);
455 
456                 // Add to result
457                 result.addCopiedFiles(DataSynchroTables.PHOTO.name(), 1);
458             } catch (IOException e) {
459                 throw new SynchroTechnicalException("Could not create operation to copy file into: " + dest.getPath(), e);
460             }
461         }
462         return true;
463     }
464 
465     private void addDeleteOperation(String srcPath,
466                                     DataSynchroContext context,
467                                     SynchroResult result,
468                                     SynchroOperationRepository buffer) {
469 
470         List<File> fileDeleteList = new ArrayList<>();
471         {
472             // Get file to delete
473             File src = new File(getTargetDirectory(context), srcPath);
474 
475             // Check if this file is already present in operations buffer
476             if (buffer instanceof SynchroTableOperation) {
477                 SynchroTableOperation operations = (SynchroTableOperation) buffer;
478                 if (operations.getFileOperations().stream()
479                         .filter(fileOperation -> fileOperation instanceof BasicFileOperation)
480                         .map(fileOperation -> ((BasicFileOperation) fileOperation))
481                         .anyMatch(basicFileOperation ->
482                                 basicFileOperation.getType() == BasicFileOperation.Type.DELETE_FILE
483                                         && basicFileOperation.getDest().equals(src)))
484                     // skip if already present
485                     return;
486             }
487 
488             // Warn if file already deleted, then continue
489             if (!src.exists()) {
490                 LOG.warn(String.format("[%s] Unable to delete the non-existent file [%s]",
491                         DataSynchroTables.PHOTO.name(),
492                         srcPath));
493                 return;
494             }
495 
496             fileDeleteList.add(src);
497 
498             // Get other photos
499             File mediumSrc = Images.getMediumImageFile(src);
500             if (mediumSrc.exists()) {
501                 fileDeleteList.add(mediumSrc);
502             }
503             File smallSrc = Images.getSmallImageFile(src);
504             if (smallSrc.exists()) {
505                 fileDeleteList.add(smallSrc);
506             }
507 
508         }
509 
510         for (File src : fileDeleteList) {
511             try {
512                 if (LOG.isDebugEnabled()) {
513                     LOG.debug(String.format("[%s] Delete file [%s]",
514                             DataSynchroTables.PHOTO.name(),
515                             srcPath));
516                 }
517 
518                 FileOperation delete;
519 
520                 // If target DB = TempDB: no lock and undo
521                 if (context.getTarget().isMirrorDatabase()) {
522                     delete = FileOperationBuilder.prepareDelete(src)
523                             .build();
524                 }
525                 // If target DB is not TempDB: apply lock and undo
526                 else {
527                     delete = FileOperationBuilder.prepareDelete(src)
528                             .withLock()
529                             .withUndo()
530                             .build();
531                 }
532                 buffer.addFileOperation(delete);
533 
534                 // Delete parent directory, is empty
535                 FileOperation deleteParentDirIfEmpty = FileOperationBuilder.prepareDeleteDir(src.getParentFile())
536                         .onlyIfEmpty()
537                         .build();
538                 buffer.addFileOperation(deleteParentDirIfEmpty);
539 
540                 // Add to result
541                 result.addDeletedFiles(DataSynchroTables.PHOTO.name(), 1);
542             } catch (IOException e) {
543                 throw new SynchroTechnicalException("Could not delete file: " + src.getPath(), e);
544             }
545         }
546     }
547 
548     private File getSourceDirectory(DataSynchroContext context) {
549 
550         if (sourceDirectory == null) {
551             sourceDirectory = context.getSource().getDbPhotoDirectory();
552             if (sourceDirectory == null || !sourceDirectory.exists() || !sourceDirectory.isDirectory()) {
553                 throw new SynchroTechnicalException("Could not find source photo directory: " + sourceDirectory);
554             }
555         }
556         return sourceDirectory;
557     }
558 
559     private File getTargetDirectory(DataSynchroContext context) {
560         if (targetDirectory == null) {
561             targetDirectory = context.getTarget().getDbPhotoDirectory();
562             if (!targetDirectory.exists() || !targetDirectory.isDirectory()) {
563                 try {
564                     FileUtils.forceMkdir(targetDirectory);
565                 } catch (IOException e) {
566                     throw new SynchroTechnicalException("Could not create directory " + targetDirectory.getPath(), e);
567                 }
568             }
569         }
570         return targetDirectory;
571     }
572 
573     /**
574      * <p>
575      * getRemoteIdAndParentIdFromSampleId.
576      * </p>
577      *
578      * @param dao      a {@link fr.ifremer.common.synchro.dao.SynchroBaseDao} object.
579      * @param sampleId a long.
580      * @return an array of {@link java.lang.Number} objects.
581      * @throws java.sql.SQLException if any.
582      */
583     private Number[] getRemoteIdAndParentIdFromSampleId(SynchroBaseDao dao, long sampleId) throws SQLException {
584         if (selectRemoteIdAndParentIdsFromSampleIdStatement == null || selectRemoteIdAndParentIdsFromSampleIdStatement.isClosed()) {
585             selectRemoteIdAndParentIdsFromSampleIdStatement = dao.getPreparedStatement(selectRemoteIdAndParentIdsFromSampleIdQuery);
586         }
587         Number[] result = null;
588         selectRemoteIdAndParentIdsFromSampleIdStatement.setLong(1, sampleId);
589         ResultSet resultSet = null;
590         try {
591             resultSet = selectRemoteIdAndParentIdsFromSampleIdStatement.executeQuery();
592             if (resultSet.next()) {
593                 Number remoteId = null;
594                 if (resultSet.getObject(1) != null) {
595                     remoteId = (Number) resultSet.getObject(1);
596                 }
597                 Number surveyId = null;
598                 if (resultSet.getObject(2) != null) {
599                     surveyId = (Number) resultSet.getObject(2);
600                 }
601                 Number samplingOperId = null;
602                 if (resultSet.getObject(3) != null) {
603                     samplingOperId = (Number) resultSet.getObject(3);
604                 }
605                 result = new Number[]{remoteId, surveyId, samplingOperId};
606             }
607         } finally {
608             Daos.closeSilently(resultSet);
609         }
610         if (result == null)
611             throw new SynchroTechnicalException(String.format("Unable to find remote and parent ids from %s with local id = %s", DataSynchroTables.SAMPLE.name(), sampleId));
612         return result;
613     }
614 
615     /**
616      * <p>
617      * initSelectRemoteIdAndParentIdFromSampleIdQuery.
618      * </p>
619      * FIXME : attention SURVEY_ID n'est pas dans le table SAMPLE (à modifier aussi : MeasurementAbstractInterceptor)
620      *
621      * @return a {@link java.lang.String} object.
622      */
623     private String initSelectRemoteIdAndParentIdFromSampleIdQuery() {
624         return String.format("select %s, %s, %s from %s where %s = ?",
625                 DatabaseColumns.REMOTE_ID.name(),
626                 DatabaseColumns.SURVEY_ID.name(),
627                 DatabaseColumns.SAMPLING_OPER_ID.name(),
628                 DataSynchroTables.SAMPLE.name(),
629                 DatabaseColumns.SAMPLE_ID.name()
630         );
631     }
632 
633     /**
634      * <p>
635      * getRemoteIdAndParentIdFromSamplingOperId.
636      * </p>
637      *
638      * @param dao            a {@link fr.ifremer.common.synchro.dao.SynchroBaseDao} object.
639      * @param samplingOperId a long.
640      * @return an array of {@link java.lang.Number} objects.
641      * @throws java.sql.SQLException if any.
642      */
643     private Number[] getRemoteIdAndParentIdFromSamplingOperId(SynchroBaseDao dao, long samplingOperId) throws SQLException {
644         if (selectParentIdFromSamplingOperIdStatement == null || selectParentIdFromSamplingOperIdStatement.isClosed()) {
645             selectParentIdFromSamplingOperIdStatement = dao.getPreparedStatement(selectRemoteIdAndParentIdFromSamplingOperIdQuery);
646         }
647         Number[] result = null;
648         selectParentIdFromSamplingOperIdStatement.setLong(1, samplingOperId);
649         ResultSet resultSet = null;
650         try {
651             resultSet = selectParentIdFromSamplingOperIdStatement.executeQuery();
652             if (resultSet.next()) {
653                 Number remoteId = null;
654                 if (resultSet.getObject(1) != null) {
655                     remoteId = (Number) resultSet.getObject(1);
656                 }
657                 Number surveyId = null;
658                 if (resultSet.getObject(2) != null) {
659                     surveyId = (Number) resultSet.getObject(2);
660                 }
661                 result = new Number[]{remoteId, surveyId};
662             }
663         } finally {
664             Daos.closeSilently(resultSet);
665         }
666         if (result == null)
667             throw new SynchroTechnicalException(String.format("Unable to find remote and parent ids from %s with local id = %s", DataSynchroTables.SAMPLING_OPERATION.name(), samplingOperId));
668         return result;
669     }
670 
671     /**
672      * <p>
673      * initSelectRemoteIdAndParentIdFromSamplingOperIdQuery.
674      * </p>
675      *
676      * @return a {@link java.lang.String} object.
677      */
678     private String initSelectRemoteIdAndParentIdFromSamplingOperIdQuery() {
679         return String.format("select %s, %s from %s where %s = ?",
680                 DatabaseColumns.REMOTE_ID.name(),
681                 DatabaseColumns.SURVEY_ID.name(),
682                 DataSynchroTables.SAMPLING_OPERATION.name(),
683                 DatabaseColumns.SAMPLING_OPER_ID.name()
684         );
685     }
686 
687     /**
688      * <p>
689      * getRemoteIdFromSurveyId.
690      * </p>
691      *
692      * @param dao      a {@link fr.ifremer.common.synchro.dao.SynchroBaseDao} object.
693      * @param surveyId a long.
694      * @return a {@link java.lang.Number} object.
695      * @throws java.sql.SQLException if any.
696      */
697     private Number getRemoteIdFromSurveyId(SynchroBaseDao dao, long surveyId) throws SQLException {
698         Number remoteId = dao.getUniqueTyped(selectRemoteIdBySurveyIdQuery, new Object[]{surveyId});
699         if (remoteId == null)
700             throw new SynchroTechnicalException(String.format("Unable to find remote id from %s with local id = %s", DataSynchroTables.SURVEY.name(), surveyId));
701         return remoteId;
702     }
703 
704     /**
705      * <p>
706      * initSelectRemoteIdFromSurveyId.
707      * </p>
708      *
709      * @return a {@link java.lang.String} object.
710      */
711     private String initSelectRemoteIdFromSurveyId() {
712         return String.format("select %s from %s where %s = ?",
713                 DatabaseColumns.REMOTE_ID.name(),
714                 DataSynchroTables.SURVEY.name(),
715                 DatabaseColumns.SURVEY_ID.name());
716     }
717 
718     private Number getLocalIdFromSurveyId(SynchroBaseDao dao, long remoteId) throws SQLException {
719         Number localId = dao.getUniqueTyped(selectLocalIdBySurveyIdQuery, new Object[]{remoteId});
720         if (localId == null)
721             throw new SynchroTechnicalException(String.format("Unable to find local id from %s with remote id = %s", DataSynchroTables.SURVEY.name(), remoteId));
722         return localId;
723     }
724 
725     private String initSelectLocalIdFromSurveyId() {
726         return String.format("select %s from %s where %s = ?",
727                 DatabaseColumns.SURVEY_ID.name(),
728                 DataSynchroTables.SURVEY.name(),
729                 DatabaseColumns.REMOTE_ID.name()
730         );
731     }
732 
733     private Number getLocalIdFromSamplingOperId(SynchroBaseDao dao, long remoteId) throws SQLException {
734         Number localId = dao.getUniqueTyped(selectLocalIdBySamplingOperIdQuery, new Object[]{remoteId});
735         if (localId == null)
736             throw new SynchroTechnicalException(String.format("Unable to find local id from %s with remote id = %s", DataSynchroTables.SAMPLING_OPERATION.name(), remoteId));
737         return localId;
738     }
739 
740     private String initSelectLocalIdFromSamplingOperId() {
741         return String.format("select %s from %s where %s = ?",
742                 DatabaseColumns.SAMPLING_OPER_ID.name(),
743                 DataSynchroTables.SAMPLING_OPERATION.name(),
744                 DatabaseColumns.REMOTE_ID.name()
745         );
746     }
747 
748     private Number getLocalIdFromSampleId(SynchroBaseDao dao, long remoteId) throws SQLException {
749         Number localId = dao.getUniqueTyped(selectLocalIdBySampleIdQuery, new Object[]{remoteId});
750         if (localId == null)
751             throw new SynchroTechnicalException(String.format("Unable to find local id from %s with remote id = %s", DataSynchroTables.SAMPLE.name(), remoteId));
752         return localId;
753     }
754 
755     private String initSelectLocalIdFromSampleId() {
756         return String.format("select %s from %s where %s = ?",
757                 DatabaseColumns.SAMPLE_ID.name(),
758                 DataSynchroTables.SAMPLE.name(),
759                 DatabaseColumns.REMOTE_ID.name()
760         );
761     }
762 
763 }