1 package fr.ifremer.quadrige2.synchro.service.client;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import com.google.common.base.Function;
27 import com.google.common.base.Preconditions;
28 import com.google.common.base.Predicate;
29 import com.google.common.collect.*;
30 import fr.ifremer.common.synchro.config.SynchroConfiguration;
31 import fr.ifremer.common.synchro.dao.DataIntegrityViolationOnDeleteException;
32 import fr.ifremer.common.synchro.meta.SynchroTableMetadata;
33 import fr.ifremer.common.synchro.service.RejectedRow;
34 import fr.ifremer.common.synchro.service.SynchroContext;
35 import fr.ifremer.common.synchro.service.SynchroDatabaseConfiguration;
36 import fr.ifremer.common.synchro.service.SynchroResult;
37 import fr.ifremer.common.synchro.type.ProgressionModel;
38 import fr.ifremer.quadrige2.core.config.Quadrige2Configuration;
39 import fr.ifremer.quadrige2.core.dao.administration.user.PrivilegeCode;
40 import fr.ifremer.quadrige2.core.dao.data.survey.SurveyExtendDao;
41 import fr.ifremer.quadrige2.core.dao.referential.ReferentialJdbcDao;
42 import fr.ifremer.quadrige2.core.dao.referential.ReferentialJdbcDaoImpl;
43 import fr.ifremer.quadrige2.core.dao.referential.StatusCode;
44 import fr.ifremer.quadrige2.core.dao.technical.Daos;
45 import fr.ifremer.quadrige2.core.dao.technical.DatabaseSchemaDao;
46 import fr.ifremer.quadrige2.core.dao.technical.DateVersions;
47 import fr.ifremer.quadrige2.core.exception.DatabaseSchemaUpdateException;
48 import fr.ifremer.quadrige2.core.exception.Quadrige2BusinessException;
49 import fr.ifremer.quadrige2.core.exception.Quadrige2TechnicalException;
50 import fr.ifremer.quadrige2.core.service.administration.user.UserService;
51 import fr.ifremer.quadrige2.core.service.decorator.DecoratorService;
52 import fr.ifremer.quadrige2.core.vo.data.survey.LightSurveyVO;
53 import fr.ifremer.quadrige2.synchro.dao.SynchroClientDao;
54 import fr.ifremer.quadrige2.synchro.meta.administration.ProgramStrategySynchroTables;
55 import fr.ifremer.quadrige2.synchro.meta.data.DataSynchroTables;
56 import fr.ifremer.quadrige2.synchro.meta.referential.CampaignOccasionSynchroTables;
57 import fr.ifremer.quadrige2.synchro.meta.referential.ReferentialSynchroTables;
58 import fr.ifremer.quadrige2.synchro.meta.system.ContextAndFilterSynchroTables;
59 import fr.ifremer.quadrige2.synchro.meta.system.RuleSynchroTables;
60 import fr.ifremer.quadrige2.synchro.meta.system.TechnicalSynchroTables;
61 import fr.ifremer.quadrige2.synchro.service.SynchroDirection;
62 import fr.ifremer.quadrige2.synchro.service.client.vo.SynchroClientExportResult;
63 import fr.ifremer.quadrige2.synchro.service.client.vo.SynchroClientExportToFileResult;
64 import fr.ifremer.quadrige2.synchro.service.client.vo.SynchroClientImportFromFileResult;
65 import fr.ifremer.quadrige2.synchro.service.client.vo.SynchroClientImportResult;
66 import fr.ifremer.quadrige2.synchro.service.data.DataSynchroContext;
67 import fr.ifremer.quadrige2.synchro.service.data.DataSynchroService;
68 import fr.ifremer.quadrige2.synchro.service.referential.ReferentialSynchroContext;
69 import fr.ifremer.quadrige2.synchro.service.referential.ReferentialSynchroService;
70 import fr.ifremer.quadrige2.synchro.vo.SynchroChangesVO;
71 import fr.ifremer.quadrige2.synchro.vo.SynchroDateOperatorVO;
72 import fr.ifremer.quadrige2.synchro.vo.SynchroImportContextVO;
73 import org.apache.commons.collections4.CollectionUtils;
74 import org.apache.commons.collections4.MapUtils;
75 import org.apache.commons.io.FileUtils;
76 import org.apache.commons.lang3.StringUtils;
77 import org.apache.commons.lang3.time.DateUtils;
78 import org.apache.commons.logging.Log;
79 import org.apache.commons.logging.LogFactory;
80 import org.hibernate.cfg.Environment;
81 import org.hibernate.dialect.Dialect;
82 import org.nuiton.decorator.Decorator;
83 import org.nuiton.i18n.I18n;
84 import org.nuiton.jaxx.application.type.ApplicationProgressionModel;
85 import org.nuiton.util.ZipUtil;
86 import org.springframework.beans.factory.annotation.Autowired;
87 import org.springframework.context.annotation.Lazy;
88 import org.springframework.jdbc.datasource.DataSourceUtils;
89 import org.springframework.stereotype.Service;
90 import org.springframework.transaction.interceptor.TransactionInterceptor;
91
92 import javax.annotation.Nullable;
93 import javax.annotation.Resource;
94 import javax.sql.DataSource;
95 import java.beans.PropertyChangeEvent;
96 import java.beans.PropertyChangeListener;
97 import java.io.File;
98 import java.io.IOException;
99 import java.nio.charset.Charset;
100 import java.sql.Connection;
101 import java.sql.SQLException;
102 import java.sql.Timestamp;
103 import java.util.*;
104
105 import static org.nuiton.i18n.I18n.t;
106
107
108
109
110
111
112
113 @Service("synchroClientService")
114 @Lazy
115 public class SynchroClientServiceImpl implements SynchroClientInternalService {
116
117 private static final String LOCAL_DB_VERSION_FILE = "version.appup";
118 private static final String TABLE_SURVEY = "SURVEY";
119
120 private static final Log log = LogFactory.getLog(SynchroClientServiceImpl.class);
121
122 @Resource(name = "databaseSchemaDao")
123 private DatabaseSchemaDao dbSchemaDao;
124
125 @Resource(name = "surveyDao")
126 private SurveyExtendDao surveyDao;
127
128 @Resource(name = "synchroClientDao")
129 private SynchroClientDao synchroClientDao;
130
131 @Resource(name = "dataSynchroService")
132 private DataSynchroService dataSynchroService;
133
134 @Resource(name = "userService")
135 private UserService userService;
136
137 @Resource(name = "referentialSynchroService")
138 private ReferentialSynchroService referentialSynchroService;
139
140 @Resource
141 private SynchroHistoryService synchroHistoryService;
142
143 @Resource
144 private DataSource dataSource;
145
146 private DecoratorService decoratorService;
147
148 @Resource(name = "synchroClientService")
149 private SynchroClientInternalService synchroClientInternalService;
150
151 private final Quadrige2Configuration config;
152 private final SynchroConfiguration synchroConfig;
153
154
155
156
157
158
159
160
161
162
163
164
165
166 @Autowired
167 public SynchroClientServiceImpl(Quadrige2Configuration config, SynchroConfiguration synchroConfig, DecoratorService decoratorService) {
168 super();
169 this.config = config;
170 this.synchroConfig = synchroConfig;
171 this.decoratorService = decoratorService;
172 }
173
174
175 @Override
176 public SynchroClientImportResult importFromTempDb(
177 int userId,
178 File dbDirToImport,
179 SynchroImportContextVO importContext,
180 SynchroRejectedRowResolver dataRejectResolver,
181 ApplicationProgressionModel progressionModel,
182 int progressionModelMaxCount) {
183
184 SynchroClientImportResult result = null;
185 try {
186 result = synchroClientInternalService.importFromTempDbTransactional(
187 userId,
188 dbDirToImport,
189 importContext,
190 dataRejectResolver,
191 progressionModel,
192 progressionModelMaxCount);
193
194 } catch (DataIntegrityViolationOnDeleteException deleteException) {
195
196
197 SynchroDatabaseConfiguration target = new SynchroDatabaseConfiguration(Quadrige2Configuration.getInstance().getConnectionProperties(),
198 true);
199 handleDeleteException(deleteException, target);
200 }
201
202 return result;
203 }
204
205
206 @Override
207 public SynchroClientImportResult importFromTempDbTransactional(
208 int userId,
209 File dbDirToImport,
210 SynchroImportContextVO importContext,
211 SynchroRejectedRowResolver dataRejectResolver,
212 ApplicationProgressionModel progressionModel,
213 int progressionModelMaxCount) {
214 Preconditions.checkNotNull(progressionModel);
215 Preconditions.checkNotNull(importContext);
216 SynchroClientImportResult result = new SynchroClientImportResult();
217
218 int progressionStepCount;
219 if (importContext.isWithReferential() && importContext.isWithData()) {
220 progressionStepCount = progressionModelMaxCount / 3;
221 } else if (importContext.isWithReferential()) {
222 progressionStepCount = progressionModelMaxCount / 2;
223 } else {
224 progressionStepCount = progressionModelMaxCount;
225 }
226 int progressionStepNumber = 1;
227
228 Properties tempDbConnectionProperties = getConnectionPropertiesFromDbDirectory(dbDirToImport);
229
230 File versionFile = new File(dbDirToImport, LOCAL_DB_VERSION_FILE);
231 String newVersion = null;
232 try {
233 newVersion = FileUtils.readFileToString(versionFile, Charset.defaultCharset()).trim();
234 } catch (IOException ex) {
235 log.warn(t("quadrige2.error.read.file", versionFile.getAbsolutePath()));
236 }
237
238 Date synchroDate = StringUtils.isEmpty(newVersion) ? new Date() : DateVersions.convertVersion2Date(newVersion,
239 Quadrige2Configuration.getInstance().getDbTimezone());
240
241 try {
242
243 if (importContext.isWithReferential()) {
244 ReferentialSynchroContext referentialContext = createContextAndImportReferentialWithoutDelete(userId,
245 dbDirToImport,
246 true,
247 progressionModel,
248 progressionStepNumber++,
249 progressionStepCount);
250 result.setReferentialContext(referentialContext);
251 }
252
253
254 if (importContext.isWithData()) {
255
256 DataSynchroContext temp2LocalContext = createContextAndImportDataFromTempDB(
257 userId,
258 dbDirToImport,
259 importContext,
260 progressionModel, progressionStepNumber++,
261 progressionStepCount);
262
263
264 resolveRejectsAndFinishImportData(temp2LocalContext, dataRejectResolver);
265
266 result.setDataContext(temp2LocalContext);
267 }
268
269
270 if (importContext.isWithReferential()) {
271
272 updateContextAndImportReferentialDelete(
273 result.getReferentialContext(),
274 true,
275 progressionModel,
276 progressionStepNumber++,
277 progressionStepCount);
278 }
279
280
281
282 if (importContext.isWithData()) {
283 result.getDataContext().setEnableInsertOrUpdate(true);
284 result.getDataContext().setEnableDelete(true);
285
286 Date newSynchronizationDate = computeDataSynchronizationDate(result.getDataResult().getRejectedRows(), synchroDate,
287 importContext.getDataUpdateDate());
288 result.setDataSynchronizationDate(newSynchronizationDate);
289 }
290 if (importContext.isWithReferential()) {
291 result.getReferentialContext().setEnableInsertOrUpdate(true);
292 result.getReferentialContext().setEnableDelete(true);
293
294 result.setReferentialSynchronizationDate(DateUtils.addSeconds(synchroDate, config.getImportReferentialUpdateDateOffsetInSecond()));
295 }
296 } finally {
297 shutdownDatabaseSilently(tempDbConnectionProperties);
298 }
299
300
301 synchroHistoryService.save(userId, result);
302
303 return result;
304 }
305
306
307 @Override
308 public SynchroClientImportResult importFromServerDatabase(int userId,
309 SynchroImportContextVO importContext,
310 SynchroRejectedRowResolver dataRejectResolver,
311 ApplicationProgressionModel progressionModel,
312 int progressionModelMaxCount) {
313
314 SynchroClientImportResult result = null;
315 try {
316 synchroClientInternalService.importFromServerDatabaseTransactional(
317 userId,
318 importContext,
319 dataRejectResolver,
320 progressionModel,
321 progressionModelMaxCount);
322
323 } catch (DataIntegrityViolationOnDeleteException deleteException) {
324
325
326 SynchroDatabaseConfiguration target = new SynchroDatabaseConfiguration(Quadrige2Configuration.getInstance().getConnectionProperties(),
327 true);
328 handleDeleteException(deleteException, target);
329 }
330
331 return result;
332 }
333
334
335 @Override
336 public SynchroClientImportResult importFromServerDatabaseTransactional(int userId, SynchroImportContextVO importContext,
337 SynchroRejectedRowResolver dataRejectResolver, ApplicationProgressionModel progressionModel, int progressionModelMaxCount) {
338 Preconditions.checkNotNull(dataRejectResolver);
339 Preconditions.checkNotNull(progressionModel);
340 Preconditions.checkNotNull(importContext);
341 SynchroClientImportResult result = new SynchroClientImportResult();
342
343 Properties sourceConnectionProperties = synchroConfig.getImportConnectionProperties();
344
345 boolean withReferential = importContext.isWithReferential();
346 boolean withData = importContext.isWithData();
347 Properties tempDbConnectionProperties = null;
348 File tempDbDirectory = null;
349
350 Date synchronizationDate = getServerCurrentTimestamp(sourceConnectionProperties);
351
352 if (withData) {
353 tempDbDirectory = new File(config.getSynchronizationDirectory(), String.format("%s/import/db-%s",
354 userId,
355 DateVersions.convertDate2Version(synchronizationDate).toString()
356 ));
357 tempDbConnectionProperties = createTempEmptyDb(tempDbDirectory);
358 }
359
360 int progressionStepCount;
361 if (withReferential && withData) {
362 progressionStepCount = progressionModelMaxCount / 4;
363 } else {
364 progressionStepCount = progressionModelMaxCount / 2;
365 }
366 int progressionStepNumber = 1;
367
368 try {
369
370 if (withReferential) {
371
372 ReferentialSynchroContext referentialContext = createContextAndImportReferentialWithoutDelete(
373 userId,
374 sourceConnectionProperties,
375 importContext,
376 false,
377 progressionModel,
378 progressionStepNumber++,
379 progressionStepCount);
380 result.setReferentialContext(referentialContext);
381 }
382
383
384 if (withData) {
385
386 DataSynchroContext server2TempContext = createContextAndImportDataFromServerToTempDB(
387 userId,
388 sourceConnectionProperties,
389 tempDbConnectionProperties,
390 importContext,
391 progressionModel,
392 progressionStepNumber++,
393 progressionStepCount);
394
395
396 DataSynchroContext temp2LocalContext = createContextAndImportDataFromTempDB(
397 userId,
398 tempDbConnectionProperties,
399 importContext,
400 progressionModel,
401 progressionStepNumber++,
402 progressionStepCount);
403
404
405 resolveRejectsAndFinishImportData(temp2LocalContext, dataRejectResolver);
406
407 result.setDataContext(temp2LocalContext);
408 }
409
410
411 if (withReferential) {
412 updateContextAndImportReferentialDelete(
413 result.getReferentialContext(),
414 false,
415 progressionModel,
416 progressionStepNumber++,
417 progressionStepCount);
418 }
419
420
421
422 {
423 if (importContext.isWithData()) {
424 result.getDataContext().setEnableInsertOrUpdate(true);
425 result.getDataContext().setEnableDelete(true);
426
427 Date newDataSynchrodDate = computeDataSynchronizationDate(result.getDataResult().getRejectedRows(), synchronizationDate,
428 importContext.getDataUpdateDate());
429 result.setDataSynchronizationDate(newDataSynchrodDate);
430
431 }
432 if (importContext.isWithReferential()) {
433 result.getReferentialContext().setEnableInsertOrUpdate(true);
434 result.getReferentialContext().setEnableDelete(true);
435
436 result.setReferentialSynchronizationDate(DateUtils.addSeconds(synchronizationDate,
437 config.getImportReferentialUpdateDateOffsetInSecond()));
438 }
439 }
440 } finally {
441 if (withData) {
442 shutdownDatabaseSilently(tempDbConnectionProperties);
443 deleteSilently(tempDbDirectory);
444 }
445 }
446
447 return result;
448 }
449
450
451 @Override
452 public SynchroChangesVO getImportFileInsertAndUpdateChangesTransactional(int userId, File dbZipFile, SynchroImportContextVO importContext,
453 ApplicationProgressionModel progressionModel, int progressionModelMaxCount, boolean keepTempDirectory) {
454 Preconditions.checkNotNull(dbZipFile);
455 Preconditions.checkNotNull(importContext);
456 Preconditions.checkNotNull(progressionModel);
457 Preconditions.checkArgument(progressionModelMaxCount > 0);
458
459 if (log.isInfoEnabled()) {
460 log.info(I18n.t("quadrige2.service.synchro.changelog"));
461 }
462
463 int progressionStepCount;
464 if (importContext.isWithReferential() && importContext.isWithData()) {
465 progressionStepCount = (progressionModelMaxCount - (2 )) / 2;
466 } else {
467 progressionStepCount = progressionModelMaxCount - (2 );
468 }
469 int progressionStepNumber = 1;
470
471
472 checkValidImportFile(dbZipFile);
473
474 File tempDirectory = new File(
475 config.getSynchroImportDirectoryByUser(userId),
476 config.getSynchroZipFilePrefix() + DateVersions.convertDate2Version(new Date()).toString());
477
478
479 File changesFile = new File(tempDirectory, "changes.properties");
480 if (changesFile.exists()) {
481 try {
482 FileUtils.forceDelete(changesFile);
483 } catch (IOException e) {
484 throw new Quadrige2TechnicalException("Unable to create change log file :" + changesFile.getPath(), e);
485 }
486 }
487
488
489 try {
490 progressionModel.setMessage(t("quadrige2.synchro.progress.uncompress"));
491
492 FileUtils.forceMkdir(tempDirectory);
493 ZipUtil.uncompress(dbZipFile, tempDirectory);
494
495 progressionModel.increments(1);
496 } catch (IOException e) {
497 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.dbZipFile.notZipFile", dbZipFile.getPath()), e);
498 }
499
500
501 File dbDirToImport = Daos.checkAndNormalizeDbDirectory(tempDirectory);
502
503 Properties tempDbConnectionProperties = getConnectionPropertiesFromDbDirectory(dbDirToImport);
504
505
506 SynchroChangesVO result = new SynchroChangesVO();
507 result.setConnectionProperties(tempDbConnectionProperties);
508
509
510 TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
511
512 try {
513 Map<String, Map<String, Map<String, Object>>> dataRemapValues = null;
514
515
516 if (importContext.isWithReferential()) {
517 ReferentialSynchroContext referentialSynchroContext = createContextAndImportReferentialFromFile(
518 userId,
519 dbDirToImport,
520 changesFile,
521 true,
522 null,
523 t("quadrige2.service.synchro.changelog.message"),
524 progressionModel,
525 progressionStepNumber++,
526 progressionStepCount);
527
528
529 resolveFileReferentialRejectsAndFinishImportFromFile(referentialSynchroContext, newReferentialSynchroRejectedRowResolver());
530
531
532 dataRemapValues = referentialSynchroContext.getResult().getSourceMissingUpdates();
533
534
535 result.addRejects(referentialSynchroContext.getResult().getRejectedRows());
536 }
537
538
539 if (importContext.isWithData()) {
540 DataSynchroContext dataContext = createContextAndImportFromFile(
541 userId,
542 dbDirToImport,
543 changesFile,
544 true,
545 null,
546 dataRemapValues,
547 false,
548 t("quadrige2.service.synchro.changelog.message"),
549 progressionModel,
550 progressionStepNumber++,
551 progressionStepCount);
552
553
554 result.addRejects(dataContext.getResult().getRejectedRows());
555 }
556
557
558 progressionModel.setMessage(t("quadrige2.synchro.progress.changeLog"));
559 if (changesFile.exists()) {
560
561 result.addFromFile(changesFile);
562
563
564 FileUtils.deleteQuietly(changesFile);
565 }
566
567 if (!keepTempDirectory) {
568 FileUtils.deleteQuietly(tempDirectory);
569 }
570
571 progressionModel.increments(1);
572
573 return result;
574
575 } finally {
576 shutdownDatabaseSilently(tempDbConnectionProperties);
577 }
578 }
579
580
581 @Override
582 public SynchroChangesVO getImportFileReferentialDeleteChangesTransactional(int userId, File dbZipFile, SynchroImportContextVO importContext,
583 ApplicationProgressionModel progressionModel, int progressionModelMaxCount, boolean keepTempDirectory) {
584
585 Preconditions.checkNotNull(dbZipFile);
586 Preconditions.checkNotNull(importContext);
587 Preconditions.checkNotNull(progressionModel);
588 Preconditions.checkArgument(progressionModelMaxCount > 0);
589
590 if (log.isInfoEnabled()) {
591 log.info(I18n.t("quadrige2.service.synchro.changelog"));
592 }
593
594 int progressionStepCount = progressionModelMaxCount - (2 );
595 int progressionStepNumber = 1;
596
597
598 checkValidImportFile(dbZipFile);
599
600 File tempDirectory = new File(
601 config.getSynchroImportDirectoryByUser(userId),
602 config.getSynchroZipFilePrefix() + DateVersions.convertDate2Version(new Date()).toString());
603
604
605 File changesFile = new File(tempDirectory, "changes.properties");
606 if (changesFile.exists()) {
607 try {
608 FileUtils.forceDelete(changesFile);
609 } catch (IOException e) {
610 throw new Quadrige2TechnicalException("Unable to create change log file :" + changesFile.getPath(), e);
611 }
612 }
613
614
615 try {
616 progressionModel.setMessage(t("quadrige2.synchro.progress.uncompress"));
617
618 FileUtils.forceMkdir(tempDirectory);
619 ZipUtil.uncompress(dbZipFile, tempDirectory);
620
621 progressionModel.increments(1);
622 } catch (IOException e) {
623 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.dbZipFile.notZipFile", dbZipFile.getPath()), e);
624 }
625
626
627 File dbDirToImport = Daos.checkAndNormalizeDbDirectory(tempDirectory);
628
629 Properties tempDbConnectionProperties = getConnectionPropertiesFromDbDirectory(dbDirToImport);
630
631
632 SynchroChangesVO result = new SynchroChangesVO();
633 result.setConnectionProperties(tempDbConnectionProperties);
634
635
636 TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
637
638 try {
639
640
641 if (importContext.isWithReferential()) {
642 ReferentialSynchroContext referentialSynchroContext = createContextAndImportReferentialDeleteFromFile(
643 userId,
644 dbDirToImport,
645 changesFile,
646 true,
647 null,
648 t("quadrige2.service.synchro.changelog.message"),
649 progressionModel,
650 progressionStepNumber++,
651 progressionStepCount);
652
653
654 result.addRejects(referentialSynchroContext.getResult().getRejectedRows());
655 }
656
657
658 progressionModel.setMessage(t("quadrige2.synchro.progress.changeLog"));
659 if (changesFile.exists()) {
660
661 result.addFromFile(changesFile);
662
663
664 FileUtils.deleteQuietly(changesFile);
665 }
666
667 if (!keepTempDirectory) {
668 FileUtils.deleteQuietly(tempDirectory);
669 }
670
671 progressionModel.increments(1);
672
673 return result;
674
675 } finally {
676 shutdownDatabaseSilently(tempDbConnectionProperties);
677 }
678 }
679
680
681 @Override
682 public void cleanUpUnusedData(int userId) {
683
684 List<Integer> personIdsToRemove = Lists.newArrayList();
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714 List<Integer> observedLocationIdsToRemove = surveyDao.getCleanableSurveyIds();
715 if (CollectionUtils.isNotEmpty(observedLocationIdsToRemove)) {
716 surveyDao.removeByIds(observedLocationIdsToRemove);
717 }
718
719
720 if (CollectionUtils.isNotEmpty(personIdsToRemove)) {
721 for (Integer personIdToRemove : personIdsToRemove) {
722 File personDirectory = getSynchroDirectoryByUser(personIdToRemove);
723
724 if (personDirectory.exists()) {
725 FileUtils.deleteQuietly(personDirectory);
726 }
727 }
728 }
729 }
730
731
732 @Override
733 public SynchroClientExportResult exportDataToTempDb(int userId, Set<String> programCodes, ApplicationProgressionModel progressionModel,
734 int progressionModelMaxCount) {
735
736 Preconditions.checkNotNull(progressionModel);
737
738 SynchroClientExportResult result = new SynchroClientExportResult();
739
740
741 File tempDbDirectory = new File(
742 config.getSynchroExportDirectoryByUser(userId),
743 "quadrige2-db-" + DateVersions.convertDate2Version(new Date()).toString());
744
745 Properties tempDbConnectionProperties = createTempEmptyDb(tempDbDirectory);
746
747 if (!Daos.isValidConnectionProperties(tempDbConnectionProperties)) {
748 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.create"));
749 }
750
751 result.setTempDbExportDirectory(tempDbDirectory);
752
753
754 int progressionStepCount = progressionModelMaxCount;
755 int progressionStepNumber = 1;
756
757 try {
758
759 DataSynchroContext dataContext = createContextAndExportDataToTempDb(tempDbConnectionProperties,
760 userId,
761 programCodes,
762 progressionModel,
763 progressionStepNumber++,
764 progressionStepCount);
765
766 result.setDataContext(dataContext);
767
768 } finally {
769 shutdownDatabaseSilently(tempDbConnectionProperties);
770 }
771
772 return result;
773 }
774
775
776 @Override
777 public SynchroClientExportResult exportNationalProgramsToTempDb(int userId,
778 Set<String> programCodes,
779
780 ApplicationProgressionModel progressionModel, int progressionModelMaxCount) {
781 Preconditions.checkNotNull(progressionModel);
782
783 SynchroClientExportResult result = new SynchroClientExportResult();
784
785
786 File tempDbDirectory = new File(
787 config.getSynchroExportDirectoryByUser(userId),
788 "quadrige2-db-" + DateVersions.convertDate2Version(new Date()).toString());
789
790 Properties tempDbConnectionProperties = createTempEmptyDb(tempDbDirectory);
791
792 if (!fr.ifremer.quadrige2.core.dao.technical.Daos.isValidConnectionProperties(tempDbConnectionProperties)) {
793 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.create"));
794 }
795
796 result.setTempDbExportDirectory(tempDbDirectory);
797
798
799 int progressionStepCount = progressionModelMaxCount;
800 int progressionStepNumber = 1;
801
802 try {
803
804 ReferentialSynchroContext context = createContextAndExportProgramsToTempDb(tempDbConnectionProperties,
805 userId,
806 programCodes,
807 progressionModel,
808 progressionStepNumber++,
809 progressionStepCount);
810 result.setReferentialContext(context);
811
812 } finally {
813 shutdownDatabaseSilently(tempDbConnectionProperties);
814 }
815
816 return result;
817 }
818
819
820 @Override
821 public SynchroClientExportResult exportToServerDatabase(int userId, Set<String> programCodes, SynchroRejectedRowResolver rejectResolver,
822 ApplicationProgressionModel progressionModel, int progressionModelMaxCount) {
823
824
825 File tempDbDirectory = new File(
826 config.getSynchroExportDirectoryByUser(userId),
827 "quadrige2-db-" + DateVersions.convertDate2Version(new Date()).toString());
828
829
830 Properties tempDbConnectionProperties = createTempEmptyDb(tempDbDirectory);
831
832 if (!Daos.isValidConnectionProperties(tempDbConnectionProperties)) {
833 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.create"));
834 }
835
836
837 int progressionStepCount = progressionModelMaxCount / 2;
838 int progressionStepNumber = 1;
839
840 SynchroClientExportResult result = new SynchroClientExportResult();
841
842 try {
843
844 DataSynchroContext local2tempSynchroContext = createContextAndExportDataToTempDb(tempDbConnectionProperties,
845 userId,
846 programCodes,
847 progressionModel,
848 progressionStepNumber++,
849 progressionStepCount);
850 result.setDataContext(local2tempSynchroContext);
851
852 boolean hasData = local2tempSynchroContext.getResult().getTotalTreated() > 0;
853
854
855 if (hasData) {
856
857
858
859 DataSynchroContext temp2ServerSynchroContext = createContextAndExportDataFromTempDbToServer(tempDbConnectionProperties,
860 userId,
861 progressionModel,
862 progressionStepNumber++,
863 progressionStepCount);
864 result.setServerResult(temp2ServerSynchroContext.getResult());
865
866
867 finishExportData(userId,
868 result,
869 rejectResolver,
870 false ,
871 true );
872 }
873 result.setDataContext(local2tempSynchroContext);
874
875 } finally {
876 shutdownDatabaseSilently(tempDbConnectionProperties);
877 deleteSilently(tempDbDirectory);
878 }
879
880 return result;
881 }
882
883
884 @Override
885 public boolean finishExportData(int userId, SynchroClientExportResult exportResult,
886 SynchroRejectedRowResolver rejectResolver, boolean synchroFailed, boolean runPkRevert) {
887 Preconditions.checkNotNull(exportResult.getServerResult());
888
889 boolean hasShownRejectMessage = false;
890 DataSynchroContext dataSynchroContext = exportResult.getDataContext();
891 SynchroResult serverResult = exportResult.getServerResult();
892
893
894
895 inverseRejectsSourceAndTargetPks(serverResult);
896
897 Map<RejectedRow.Cause, RejectedRow.ResolveStrategy> rejectStrategies = Maps.newHashMap();
898
899
900 Map<RejectedRow.Cause, String> rejectedRows = decorateRejectedRows(serverResult.getRejectedRows());
901
902
903 if (rejectedRows.containsKey(RejectedRow.Cause.DUPLICATE_KEY)) {
904 rejectResolver.showRejectMessage(rejectedRows, RejectedRow.Cause.DUPLICATE_KEY, synchroFailed);
905 hasShownRejectMessage = true;
906 }
907
908
909 if (rejectedRows.containsKey(RejectedRow.Cause.LOCKED)) {
910 rejectResolver.showRejectMessage(rejectedRows, RejectedRow.Cause.LOCKED, synchroFailed);
911 hasShownRejectMessage = true;
912 }
913
914
915 if (!synchroFailed) {
916 RejectedRow.ResolveStrategy deletedRowStrategy = resolveRejects(rejectedRows, RejectedRow.Cause.DELETED, rejectResolver);
917 rejectStrategies.put(RejectedRow.Cause.DELETED, deletedRowStrategy);
918 } else if (rejectedRows.containsKey(RejectedRow.Cause.DELETED)) {
919 rejectResolver.showRejectMessage(rejectedRows, RejectedRow.Cause.DELETED, true);
920 hasShownRejectMessage = true;
921 }
922
923
924 if (!synchroFailed) {
925 RejectedRow.ResolveStrategy badUpdateDateStrategy = resolveRejects(rejectedRows, RejectedRow.Cause.BAD_UPDATE_DATE, rejectResolver);
926 rejectStrategies.put(RejectedRow.Cause.BAD_UPDATE_DATE, badUpdateDateStrategy);
927 } else if (rejectedRows.containsKey(RejectedRow.Cause.BAD_UPDATE_DATE)) {
928 rejectResolver.showRejectMessage(rejectedRows, RejectedRow.Cause.BAD_UPDATE_DATE, true);
929 hasShownRejectMessage = true;
930 }
931
932 if (synchroFailed) {
933 return hasShownRejectMessage;
934 }
935
936
937
938 final SynchroResult result = serverResult;
939 SynchroDatabaseConfiguration target = dataSynchroContext.getTarget();
940 dataSynchroContext.setTarget(dataSynchroContext.getSource());
941 dataSynchroContext.setSource(null);
942
943
944 try {
945 SynchroResult tempResult = new SynchroResult();
946 dataSynchroContext.setResult(tempResult);
947
948
949
950 dataSynchroService.finish(dataSynchroContext, serverResult, rejectStrategies);
951
952
953 inverseRejectsSourceAndTargetPks(tempResult);
954
955 if (!tempResult.isSuccess()) {
956
957 result.setError(tempResult.getError());
958 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.finish"), tempResult.getError());
959 }
960
961
962 result.getRejectedRows().clear();
963 result.getSourceMissingUpdates().clear();
964 result.getSourceMissingDeletes().clear();
965 result.getRejectedRows().putAll(tempResult.getRejectedRows());
966
967 Multimap<String, String> pksToRevert = ArrayListMultimap.create(tempResult.getSourceMissingReverts());
968 if (pksToRevert.isEmpty()) {
969
970 return hasShownRejectMessage;
971 }
972
973
974 if (runPkRevert) {
975 SynchroImportContextVO importContextVO = new SynchroImportContextVO();
976 importContextVO.setWithData(true);
977 importContextVO.setWithReferential(false);
978 importContextVO.setDataPkIncludes(pksToRevert);
979 importContextVO.setDataForceEditedRowOverride(true);
980
981 ApplicationProgressionModel progressionModel = new ApplicationProgressionModel();
982 progressionModel.setCurrent(0);
983 progressionModel.setTotal(100);
984
985 importFromServerDatabase(userId, importContextVO, rejectResolver, progressionModel, 100);
986 } else {
987
988 result.getSourceMissingReverts().putAll(pksToRevert);
989 }
990
991 } finally {
992
993 dataSynchroContext.setResult(result);
994 dataSynchroContext.setSource(dataSynchroContext.getTarget());
995 dataSynchroContext.setTarget(target);
996
997
998 synchroHistoryService.save(userId, exportResult);
999 }
1000
1001 return hasShownRejectMessage;
1002 }
1003
1004
1005 @Override
1006 public SynchroClientExportToFileResult exportToFile(int userId,
1007 File file, Set<String> programCodes,
1008 boolean dirtyOnly,
1009 SynchroDateOperatorVO dateOperator,
1010 Date startDate,
1011 Date endDate,
1012 ApplicationProgressionModel progressionModel, int progressionModelMaxCount) {
1013
1014 Preconditions.checkNotNull(file);
1015 Preconditions.checkNotNull(progressionModel);
1016 Preconditions.checkArgument(progressionModelMaxCount > 4);
1017
1018
1019 File tempDirectory = new File(
1020 config.getSynchroExportDirectoryByUser(userId),
1021 config.getSynchroZipFilePrefix() + DateVersions.convertDate2Version(new Date()).toString());
1022 File tempDbDirectory = new File(tempDirectory, fr.ifremer.quadrige2.core.dao.technical.Daos.DB_DIRECTORY);
1023 Properties tempDbConnectionProperties = createTempEmptyDb(tempDbDirectory);
1024 if (!Daos.isValidConnectionProperties(tempDbConnectionProperties)) {
1025 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.create"));
1026 }
1027
1028
1029 boolean isUserLocalAdmin = userService.hasPrivilege(userId, PrivilegeCode.LOCAL_ADMINISTRATOR.getValue());
1030 boolean exportNationalProgramsAndRules = isUserLocalAdmin;
1031
1032 int progressionStepCount;
1033 if (exportNationalProgramsAndRules) {
1034
1035 progressionStepCount = (progressionModelMaxCount - 2 ) / 3;
1036 } else {
1037
1038 progressionStepCount = (progressionModelMaxCount - 2 ) / 2;
1039 }
1040 int progressionStepNumber = 1;
1041
1042 SynchroClientExportToFileResult result = new SynchroClientExportToFileResult();
1043 result.setFile(file);
1044
1045
1046 try {
1047
1048 DataSynchroContext dataSynchroContext = createContextAndExportDataToFile(tempDbConnectionProperties,
1049 userId,
1050 programCodes,
1051 dirtyOnly,
1052 dateOperator,
1053 startDate,
1054 endDate,
1055 progressionModel,
1056 progressionStepNumber++,
1057 progressionStepCount);
1058 result.setDataContext(dataSynchroContext);
1059
1060
1061 ReferentialSynchroContext referentialSynchroContext = createContextAndExportLocalReferential(
1062 userId,
1063 tempDbConnectionProperties,
1064 progressionModel,
1065 progressionStepNumber++,
1066 progressionStepCount);
1067 result.setReferentialContext(referentialSynchroContext);
1068
1069
1070 if (exportNationalProgramsAndRules) {
1071 ReferentialSynchroContext nationalProgramsAndRulesContext = createContextAndExportAdditionalReferentialToFile(
1072 userId,
1073 null ,
1074 tempDbConnectionProperties,
1075 progressionModel,
1076 progressionStepNumber++,
1077 progressionStepCount);
1078
1079
1080 referentialSynchroContext.getResult().addAll(nationalProgramsAndRulesContext.getResult());
1081 }
1082
1083
1084 shutdownDatabaseSilently(tempDbConnectionProperties);
1085
1086
1087 boolean hasDataRows = result.getDataResult().getTotalTreated() > 0;
1088 boolean hasReferentialRows = result.getReferentialResult().getTotalTreated() > 0;
1089
1090
1091 if (hasDataRows || hasReferentialRows) {
1092
1093 progressionModel.increments(t("quadrige2.synchro.progress.compress"));
1094
1095 try {
1096 ZipUtil.compress(file, tempDbDirectory);
1097 } catch (IOException e) {
1098 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.compress"), e);
1099 }
1100
1101
1102 if (hasDataRows) {
1103 progressionModel.increments(t("quadrige2.synchro.progress.finishExport"));
1104 finishExportDataToFile(result);
1105 }
1106
1107
1108 synchroHistoryService.save(userId, result);
1109 } else {
1110 progressionModel.increments(2);
1111 }
1112
1113 } finally {
1114
1115 deleteSilently(tempDbDirectory);
1116 }
1117
1118 return result;
1119 }
1120
1121
1122 @Override
1123 public SynchroClientExportToFileResult exportReferentialToFile(int userId,
1124 File file,
1125 Set<String> programCodes,
1126 ApplicationProgressionModel progressionModel,
1127 int progressionModelMaxCount) {
1128
1129 Preconditions.checkNotNull(file);
1130 Preconditions.checkNotNull(progressionModel);
1131 Preconditions.checkArgument(progressionModelMaxCount > 1);
1132
1133
1134 File tempDirectory = new File(
1135 config.getSynchroExportDirectoryByUser(userId),
1136 config.getSynchroZipFilePrefix() + DateVersions.convertDate2Version(new Date()).toString());
1137 File tempDbDirectory = new File(tempDirectory, fr.ifremer.quadrige2.core.dao.technical.Daos.DB_DIRECTORY);
1138 Properties tempDbConnectionProperties = createTempEmptyDb(tempDbDirectory);
1139 if (!Daos.isValidConnectionProperties(tempDbConnectionProperties)) {
1140 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.create"));
1141 }
1142
1143
1144 boolean isUserLocalAdmin = userService.hasPrivilege(userId, PrivilegeCode.LOCAL_ADMINISTRATOR.getValue());
1145 Preconditions.checkArgument(isUserLocalAdmin || CollectionUtils.isEmpty(programCodes),
1146 "Not implemented: only local administrator is allow to export referential with a filter on programs");
1147 boolean exportAdditionalReferential = isUserLocalAdmin;
1148
1149 int progressionStepCount;
1150 if (exportAdditionalReferential) {
1151
1152 progressionStepCount = (progressionModelMaxCount - 1 ) / 2;
1153 } else {
1154
1155 progressionStepCount = (progressionModelMaxCount - 1 );
1156 }
1157 int progressionStepNumber = 1;
1158
1159 SynchroClientExportToFileResult result = new SynchroClientExportToFileResult();
1160 result.setFile(file);
1161
1162
1163 try {
1164
1165 ReferentialSynchroContext referentialSynchroContext = createContextAndExportLocalReferential(
1166 userId,
1167 tempDbConnectionProperties,
1168 progressionModel,
1169 progressionStepNumber++,
1170 progressionStepCount);
1171 result.setReferentialContext(referentialSynchroContext);
1172
1173
1174 if (exportAdditionalReferential) {
1175 ReferentialSynchroContext programsAndRulesContext = createContextAndExportAdditionalReferentialToFile(
1176 userId,
1177 programCodes,
1178 tempDbConnectionProperties,
1179 progressionModel,
1180 progressionStepNumber++,
1181 progressionStepCount);
1182
1183
1184 referentialSynchroContext.getResult().addAll(programsAndRulesContext.getResult());
1185 }
1186
1187
1188 shutdownDatabaseSilently(tempDbConnectionProperties);
1189
1190
1191 boolean hasReferentialRows = result.getReferentialResult().getTotalTreated() > 0;
1192
1193
1194 if (hasReferentialRows) {
1195
1196 progressionModel.increments(t("quadrige2.synchro.progress.compress"));
1197 try {
1198 ZipUtil.compress(file, tempDbDirectory);
1199 } catch (IOException e) {
1200 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.compress"), e);
1201 }
1202
1203
1204 synchroHistoryService.save(userId, result);
1205 }
1206
1207 } finally {
1208
1209 deleteSilently(tempDbDirectory);
1210 }
1211
1212 return result;
1213 }
1214
1215
1216 @Override
1217 public SynchroClientExportToFileResult exportAllReferentialToFile(int userId, File file, ApplicationProgressionModel progressionModel,
1218 int progressionModelMaxCount) {
1219
1220 Preconditions.checkNotNull(file);
1221 Preconditions.checkNotNull(progressionModel);
1222 Preconditions.checkArgument(progressionModelMaxCount > 1);
1223
1224
1225 File tempDirectory = new File(
1226 config.getSynchroExportDirectoryByUser(userId),
1227 config.getSynchroZipFilePrefix() + DateVersions.convertDate2Version(new Date()).toString());
1228 File tempDbDirectory = new File(tempDirectory, fr.ifremer.quadrige2.core.dao.technical.Daos.DB_DIRECTORY);
1229 Properties tempDbConnectionProperties = createTempEmptyDb(tempDbDirectory);
1230 if (!Daos.isValidConnectionProperties(tempDbConnectionProperties)) {
1231 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.create"));
1232 }
1233
1234
1235 int progressionStepCount = (progressionModelMaxCount - 1 );
1236 int progressionStepNumber = 1;
1237
1238 SynchroClientExportToFileResult result = new SynchroClientExportToFileResult();
1239 result.setFile(file);
1240
1241
1242 try {
1243
1244
1245 {
1246 File srcDbVersionFile = new File(config.getDbDirectory(), "version.appup");
1247 if (srcDbVersionFile.exists()) {
1248 File destDbVersionFile = new File(tempDbDirectory, "version.appup");
1249 try {
1250 FileUtils.copyFile(srcDbVersionFile, destDbVersionFile);
1251 } catch (IOException e) {
1252 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.copy", srcDbVersionFile.getPath()), e);
1253 }
1254
1255 }
1256 }
1257
1258
1259 ReferentialSynchroContext referentialSynchroContext = createContextAndExportAllReferential(
1260 userId,
1261 tempDbConnectionProperties,
1262 progressionModel,
1263 progressionStepNumber++,
1264 progressionStepCount);
1265 result.setReferentialContext(referentialSynchroContext);
1266
1267
1268 shutdownDatabaseSilently(tempDbConnectionProperties);
1269
1270
1271 boolean hasReferentialRows = result.getReferentialResult().getTotalTreated() > 0;
1272
1273
1274 if (hasReferentialRows) {
1275
1276 progressionModel.increments(t("quadrige2.synchro.progress.compress"));
1277 try {
1278 ZipUtil.compress(file, tempDbDirectory);
1279 } catch (IOException e) {
1280 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.compress"), e);
1281 }
1282
1283
1284 synchroHistoryService.save(userId, result);
1285 }
1286
1287 } finally {
1288
1289 deleteSilently(tempDbDirectory);
1290 }
1291
1292 return result;
1293 }
1294
1295
1296 @Override
1297 public SynchroClientImportFromFileResult importFromFile(int userId,
1298 File file,
1299 SynchroImportContextVO importContext,
1300 SynchroRejectedRowResolver dataRejectResolver,
1301 ApplicationProgressionModel progressionModel,
1302 int progressionModelMaxCount) {
1303 Preconditions.checkNotNull(file);
1304 Preconditions.checkNotNull(importContext);
1305 Preconditions.checkNotNull(dataRejectResolver);
1306 Preconditions.checkNotNull(progressionModel);
1307 Preconditions.checkArgument(progressionModelMaxCount > 0);
1308
1309 int progressionStepCount;
1310 if (importContext.isWithReferential() && importContext.isWithData()) {
1311 progressionStepCount = progressionModelMaxCount / 2;
1312 } else {
1313 progressionStepCount = progressionModelMaxCount;
1314 }
1315 int progressionStepNumber = 1;
1316
1317 try {
1318 DataSourceUtils.getConnection(dataSource).setAutoCommit(false);
1319 } catch (SQLException ignored) {
1320 }
1321
1322 SynchroClientImportFromFileResult result = new SynchroClientImportFromFileResult();
1323 result.setFile(file);
1324
1325
1326 checkValidImportFile(file);
1327
1328 File tempDirectory = new File(
1329 config.getSynchroImportDirectoryByUser(userId),
1330 config.getSynchroZipFilePrefix() + DateVersions.convertDate2Version(new Date()).toString());
1331
1332
1333 try {
1334 progressionModel.setMessage(t("quadrige2.synchro.progress.uncompress"));
1335
1336 FileUtils.forceMkdir(tempDirectory);
1337 ZipUtil.uncompress(file, tempDirectory);
1338 } catch (IOException e) {
1339 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.file.notZipFile", file.getPath()), e);
1340 }
1341
1342
1343 File dbDirToImport = Daos.checkAndNormalizeDbDirectory(tempDirectory);
1344
1345 Properties tempDbConnectionProperties = getConnectionPropertiesFromDbDirectory(dbDirToImport);
1346
1347 try {
1348
1349 if (importContext.isWithReferential()) {
1350 ReferentialSynchroContext temp2LocalContext = createContextAndImportReferentialFromFile(
1351 userId,
1352 dbDirToImport,
1353 importContext.getReferentialPkIncludes(),
1354 progressionModel,
1355 progressionStepNumber++,
1356 progressionStepCount);
1357
1358
1359 resolveFileReferentialRejectsAndFinishImportFromFile(
1360 temp2LocalContext,
1361 newReferentialSynchroRejectedRowResolver());
1362
1363 result.setReferentialContext(temp2LocalContext);
1364 }
1365
1366
1367 if (importContext.isWithData()) {
1368
1369
1370 Map<String, Map<String, Map<String, Object>>> dataRemapValues = getDataRemapValuesFromReferentialResult(result.getReferentialResult());
1371
1372 DataSynchroContext temp2LocalContext = createContextAndImportFromFile(
1373 userId,
1374 dbDirToImport,
1375 importContext.getDataPkIncludes(),
1376 dataRemapValues,
1377 importContext.isForceDuplication(),
1378 progressionModel,
1379 progressionStepNumber++,
1380 progressionStepCount);
1381
1382
1383 resolveFileRejectsAndFinishImportFromFile(temp2LocalContext, dataRejectResolver);
1384
1385 result.setDataContext(temp2LocalContext);
1386 }
1387
1388
1389 if (importContext.isWithReferential()) {
1390
1391 updateContextAndImportReferentialDelete(
1392 result.getReferentialContext(),
1393 true,
1394 progressionModel,
1395 progressionStepNumber,
1396 progressionStepCount);
1397
1398 }
1399
1400
1401
1402 {
1403 if (importContext.isWithReferential()) {
1404 result.getReferentialContext().setEnableInsertOrUpdate(true);
1405 result.getReferentialContext().setEnableDelete(false);
1406 result.setReferentialSynchronizationDate(null);
1407 }
1408 if (importContext.isWithData()) {
1409 result.getDataContext().setEnableInsertOrUpdate(true);
1410 result.getDataContext().setEnableDelete(false);
1411 result.setDataSynchronizationDate(null);
1412 }
1413 }
1414 } finally {
1415 shutdownDatabaseSilently(tempDbConnectionProperties);
1416 }
1417
1418
1419 synchroHistoryService.save(userId, result);
1420
1421 return result;
1422 }
1423
1424
1425
1426
1427
1428
1429 @Override
1430 public SynchroChangesVO getImportFileInsertAndUpdateChanges(
1431 int userId,
1432 File dbZipFile,
1433 SynchroImportContextVO importContext,
1434 ApplicationProgressionModel progressionModel,
1435 int progressionModelMaxCount) {
1436
1437
1438 boolean keepTempDbAfter = false;
1439
1440 return synchroClientInternalService.getImportFileInsertAndUpdateChangesTransactional(
1441 userId,
1442 dbZipFile,
1443 importContext,
1444 progressionModel,
1445 progressionModelMaxCount,
1446 keepTempDbAfter);
1447 }
1448
1449
1450 @Override
1451 public SynchroChangesVO getImportFileReferentialDeleteChanges(
1452 int userId,
1453 File dbZipFile,
1454 SynchroImportContextVO importContext,
1455 ApplicationProgressionModel progressionModel,
1456 int progressionModelMaxCount) {
1457
1458
1459 boolean keepTempDbAfter = false;
1460
1461 return synchroClientInternalService.getImportFileReferentialDeleteChangesTransactional(
1462 userId,
1463 dbZipFile,
1464 importContext,
1465 progressionModel,
1466 progressionModelMaxCount,
1467 keepTempDbAfter);
1468 }
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481 protected Properties createTempEmptyDb(File tempDbDirectory) {
1482
1483
1484 String tempDbName = config.getDbName();
1485 Properties tempConnectionProperties = new Properties();
1486 tempConnectionProperties.putAll(config.getConnectionProperties());
1487 String tempDbUrl = Daos.getJdbcUrl(tempDbDirectory, tempDbName);
1488
1489
1490 String overridedTempDbUrl = config.getApplicationConfig().getOption("quadrige2.synchro.import.tempDb.jdbc.url");
1491 if (StringUtils.isNotBlank(overridedTempDbUrl)) {
1492 tempDbUrl = overridedTempDbUrl;
1493 }
1494
1495 tempConnectionProperties.setProperty(Environment.URL, tempDbUrl);
1496
1497
1498 if (Daos.isFileDatabase(tempDbUrl)) {
1499
1500 boolean isDbCreated = false;
1501
1502
1503 if (Daos.isFileDatabase(config.getJdbcURL())) {
1504
1505 String dbDirectoryFromUrl = fr.ifremer.quadrige2.core.dao.technical.Daos.getDbDirectoryFromJdbcUrl(config.getJdbcURL());
1506 File scriptFile = new File(dbDirectoryFromUrl, config.getDbName() + ".script");
1507
1508
1509
1510
1511 if (!scriptFile.exists()) {
1512 scriptFile = new File(config.getDbDirectory(), config.getDbName() + ".script");
1513 }
1514
1515
1516 if (scriptFile.exists()) {
1517
1518 dbSchemaDao.generateNewDb(tempDbDirectory, true, scriptFile, tempConnectionProperties, true
1519
1520
1521 );
1522 isDbCreated = true;
1523 }
1524 }
1525
1526
1527
1528 if (!isDbCreated) {
1529
1530
1531 dbSchemaDao.generateNewDb(tempDbDirectory, true, null, tempConnectionProperties, true);
1532
1533
1534 try {
1535 dbSchemaDao.updateSchema(tempConnectionProperties);
1536 } catch (DatabaseSchemaUpdateException e) {
1537 throw new Quadrige2TechnicalException(e.getMessage(), e);
1538 }
1539 }
1540 }
1541
1542
1543 else {
1544 try {
1545 FileUtils.forceMkdir(tempDbDirectory);
1546 } catch (IOException e) {
1547 throw new Quadrige2TechnicalException("Could not create temp DB directory", e);
1548 }
1549 }
1550
1551 return tempConnectionProperties;
1552 }
1553
1554 private ReferentialSynchroContext createContextAndImportReferentialWithoutDelete(int userId,
1555 Properties sourceConnectionProperties,
1556 SynchroImportContextVO contextVO,
1557 boolean isSourceTemporaryDb,
1558 ApplicationProgressionModel progressionModel,
1559 int progressionStepNumber, int progressionStepCount) {
1560
1561
1562 ReferentialSynchroContext synchroContext = referentialSynchroService.createSynchroContext(sourceConnectionProperties,
1563 getTimestampOrNull(contextVO.getReferentialUpdateDate()),
1564 false,
1565 true,
1566 SynchroDirection.IMPORT_TEMP2LOCAL,
1567 userId,
1568 null );
1569
1570 doImportReferential(
1571 synchroContext,
1572 isSourceTemporaryDb,
1573 t("quadrige2.service.synchro.import.referential.message"),
1574 progressionModel,
1575 progressionStepNumber,
1576 progressionStepCount);
1577
1578 return synchroContext;
1579 }
1580
1581 private ReferentialSynchroContext createContextAndImportReferentialWithoutDelete(int userId,
1582 File dbDirToImport,
1583 boolean isSourceTemporaryDb,
1584 ApplicationProgressionModel progressionModel,
1585 int progressionStepNumber,
1586 int progressionStepCount) {
1587
1588 ReferentialSynchroContext synchroContext = referentialSynchroService.createSynchroContext(dbDirToImport,
1589 null,
1590 false,
1591 true,
1592 SynchroDirection.IMPORT_TEMP2LOCAL,
1593 userId,
1594 null );
1595
1596
1597 synchroContext.setTableNamesForced(ProgramStrategySynchroTables.tableNames());
1598
1599
1600 if (config.isEnableImportTablesRules()) {
1601 Set<String> tableNames = Sets.newLinkedHashSet(synchroContext.getTableNames());
1602 tableNames.addAll(RuleSynchroTables.tableNames());
1603 synchroContext.setTableNames(tableNames);
1604 }
1605
1606
1607 doImportReferential(synchroContext,
1608 isSourceTemporaryDb,
1609 t("quadrige2.service.synchro.import.referential.message"),
1610 progressionModel,
1611 progressionStepNumber,
1612 progressionStepCount);
1613
1614 return synchroContext;
1615 }
1616
1617 private ReferentialSynchroContext createContextAndImportReferentialFromFile(int userId,
1618 File dbDirToImport,
1619 Multimap<String, String> referentialPkIncludes,
1620 ApplicationProgressionModel progressionModel,
1621 int progressionStepNumber,
1622 int progressionStepCount) {
1623 return createContextAndImportReferentialFromFile(
1624 userId,
1625 dbDirToImport,
1626 null ,
1627 false ,
1628 referentialPkIncludes,
1629 t("quadrige2.service.synchro.import.referential.message"),
1630 progressionModel,
1631 progressionStepNumber,
1632 progressionStepCount);
1633 }
1634
1635 private ReferentialSynchroContext createContextAndImportReferentialFromFile(int userId,
1636 File dbDirToImport,
1637 File changeLogFile,
1638 boolean rollbackOnly,
1639 Multimap<String, String> referentialPkIncludes,
1640 String progressionBaseMessage,
1641 ApplicationProgressionModel progressionModel,
1642 int progressionStepNumber,
1643 int progressionStepCount) {
1644
1645 ReferentialSynchroContext synchroContext = referentialSynchroService.createSynchroContext(dbDirToImport,
1646 null,
1647 false,
1648 true,
1649 SynchroDirection.IMPORT_FILE2LOCAL,
1650 userId,
1651 null );
1652
1653
1654 synchroContext.setChangeLogFile(changeLogFile);
1655
1656
1657 synchroContext.setPkIncludes(referentialPkIncludes);
1658
1659
1660 synchroContext.getTarget().setRollbackOnly(rollbackOnly);
1661
1662
1663 {
1664 Set<String> tableNames = Sets.newLinkedHashSet(synchroContext.getTableNames());
1665
1666
1667
1668 tableNames.addAll(ProgramStrategySynchroTables.tableNames());
1669
1670
1671 tableNames.addAll(RuleSynchroTables.tableNames());
1672
1673
1674
1675 tableNames.addAll(CampaignOccasionSynchroTables.tableNames());
1676
1677 synchroContext.setTableNames(tableNames);
1678 }
1679
1680
1681 {
1682 Set<String> tableNamesForced = Sets.newLinkedHashSet();
1683 if (CollectionUtils.isNotEmpty(synchroContext.getTableNamesForced())) {
1684 tableNamesForced.addAll(synchroContext.getTableNamesForced());
1685 }
1686
1687
1688 tableNamesForced.addAll(ProgramStrategySynchroTables.tableNames());
1689
1690
1691 tableNamesForced.addAll(RuleSynchroTables.tableNames());
1692
1693 synchroContext.setTableNamesForced(tableNamesForced);
1694 }
1695
1696 doImportReferential(synchroContext,
1697 true ,
1698 progressionBaseMessage,
1699 progressionModel,
1700 progressionStepNumber,
1701 progressionStepCount);
1702
1703 return synchroContext;
1704 }
1705
1706 private ReferentialSynchroContext createContextAndImportReferentialDeleteFromFile(int userId,
1707 File dbDirToImport,
1708 File changeLogFile,
1709 boolean rollbackOnly,
1710 Multimap<String, String> referentialPkIncludes,
1711 String progressionBaseMessage,
1712 ApplicationProgressionModel progressionModel,
1713 int progressionStepNumber,
1714 int progressionStepCount) {
1715
1716 ReferentialSynchroContext synchroContext = referentialSynchroService.createSynchroContext(dbDirToImport,
1717 null,
1718 true,
1719 false,
1720 SynchroDirection.IMPORT_FILE2LOCAL,
1721 userId,
1722 ImmutableSet.of(StatusCode.LOCAL_ENABLE.getValue(), StatusCode.LOCAL_DISABLE.getValue()) );
1723
1724
1725 synchroContext.setChangeLogFile(changeLogFile);
1726
1727
1728 synchroContext.setPkIncludes(referentialPkIncludes);
1729
1730
1731 synchroContext.getTarget().setRollbackOnly(rollbackOnly);
1732
1733
1734 {
1735 Set<String> tableNames = Sets.newLinkedHashSet(synchroContext.getTableNames());
1736
1737
1738
1739 tableNames.addAll(ProgramStrategySynchroTables.tableNames());
1740
1741
1742 tableNames.addAll(RuleSynchroTables.tableNames());
1743
1744 synchroContext.setTableNames(tableNames);
1745 }
1746
1747
1748 synchroContext.setTableNamesForced(new HashSet<String>());
1749
1750 doImportReferential(synchroContext,
1751 true ,
1752 progressionBaseMessage,
1753 progressionModel,
1754 progressionStepNumber,
1755 progressionStepCount);
1756
1757 return synchroContext;
1758 }
1759
1760 private void updateContextAndImportReferentialDelete(
1761 ReferentialSynchroContext synchroContext,
1762 boolean isSourceTemporaryDb,
1763 ApplicationProgressionModel progressionModel,
1764 int progressionStepNumber,
1765 int progressionStepCount) {
1766
1767
1768 synchroContext.setEnableDelete(true);
1769 synchroContext.setEnableInsertOrUpdate(false);
1770
1771
1772 SynchroResult previousResult = synchroContext.getResult();
1773 SynchroResult newResult = new SynchroResult();
1774 synchroContext.setResult(newResult);
1775
1776 doImportReferential(
1777 synchroContext,
1778 isSourceTemporaryDb,
1779 t("quadrige2.service.synchro.import.referential.delete.message"),
1780 progressionModel,
1781 progressionStepNumber,
1782 progressionStepCount);
1783
1784 previousResult.addAll(newResult);
1785 synchroContext.setResult(previousResult);
1786 }
1787
1788 private void doImportReferential(
1789 ReferentialSynchroContext synchroContext,
1790 boolean isSourceTemporaryDb,
1791 String progressionBaseMessage,
1792 ApplicationProgressionModel progressionModel,
1793 int progressionStepNumber,
1794 int progressionStepCount) {
1795 Preconditions.checkArgument(progressionStepNumber > 0);
1796
1797
1798 synchroContext.getSource().setIsMirrorDatabase(isSourceTemporaryDb);
1799
1800 synchroContext.getTarget().setIsMirrorDatabase(false);
1801 SynchroResult result = synchroContext.getResult();
1802
1803
1804 int progressionStepOffset = progressionStepCount * (progressionStepNumber - 1);
1805 addProgressionListeners(
1806 progressionBaseMessage,
1807 progressionModel,
1808 result.getProgressionModel(),
1809 progressionStepOffset,
1810 progressionStepCount);
1811
1812 referentialSynchroService.prepare(synchroContext);
1813
1814 if (!result.isSuccess()) {
1815 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.prepare"), result.getError());
1816 }
1817
1818 referentialSynchroService.synchronize(synchroContext);
1819
1820 if (!result.isSuccess()) {
1821 Exception error = result.getError();
1822
1823
1824
1825 if (error instanceof DataIntegrityViolationOnDeleteException) {
1826 DataIntegrityViolationOnDeleteException deleteException = (DataIntegrityViolationOnDeleteException) error;
1827 if (!synchroContext.isEnableDelete()) {
1828 handleDeleteException(deleteException, synchroContext.getTarget());
1829 } else {
1830 throw deleteException;
1831 }
1832 }
1833
1834 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.synchro"), error);
1835 }
1836
1837
1838 progressionModel.setCurrent(progressionStepOffset + progressionStepCount);
1839 }
1840
1841 private DataSynchroContext createContextAndImportDataFromTempDB(int userId,
1842 File dbDirToImport,
1843 SynchroImportContextVO contextVO,
1844 ApplicationProgressionModel progressionModel, int stepNumber,
1845 int progressionModelStepCount) {
1846
1847 DataSynchroContext synchroContext = dataSynchroService.createSynchroContext(
1848 dbDirToImport,
1849 SynchroDirection.IMPORT_TEMP2LOCAL,
1850 userId,
1851 null,
1852 true,
1853 true
1854 );
1855
1856
1857 synchroContext.setForceEditedRowOverride(contextVO.isDataForceEditedRowOverride());
1858
1859 doImportData(synchroContext,
1860 t("quadrige2.service.synchro.import.data.message"),
1861 progressionModel,
1862 stepNumber,
1863 progressionModelStepCount);
1864
1865 return synchroContext;
1866 }
1867
1868 private DataSynchroContext createContextAndImportDataFromTempDB(
1869 int userId,
1870 Properties sourceConnectionProperties,
1871 SynchroImportContextVO contextVO,
1872 ApplicationProgressionModel progressionModel,
1873 int stepNumber,
1874 int progressionModelStepCount) {
1875
1876 DataSynchroContext synchroContext = dataSynchroService.createSynchroContext(
1877 sourceConnectionProperties,
1878 SynchroDirection.IMPORT_TEMP2LOCAL,
1879 userId,
1880 null,
1881 true,
1882 true
1883 );
1884
1885
1886 synchroContext.setForceEditedRowOverride(contextVO.isDataForceEditedRowOverride());
1887
1888 doImportData(synchroContext,
1889 t("quadrige2.service.synchro.import.data.message"),
1890 progressionModel,
1891 stepNumber,
1892 progressionModelStepCount);
1893
1894 return synchroContext;
1895 }
1896
1897 private DataSynchroContext createContextAndImportDataFromServerToTempDB(
1898 int userId,
1899 Properties sourceConnectionProperties,
1900 Properties targetConnectionProperties,
1901 SynchroImportContextVO contextVO,
1902 ApplicationProgressionModel progressionModel,
1903 int stepNumber,
1904 int progressionModelStepCount) {
1905 Preconditions.checkNotNull(sourceConnectionProperties);
1906 Preconditions.checkNotNull(targetConnectionProperties);
1907
1908 Timestamp lastDataUpdateDate = getTimestampOrNull(contextVO.getDataUpdateDate());
1909
1910
1911
1912
1913 boolean enableDelete = (lastDataUpdateDate != null)
1914 || !synchroClientDao.isAllTablesEmpty(DataSynchroTables.getImportTablesIncludes());
1915
1916 DataSynchroContext synchroContext = dataSynchroService.createSynchroContext(
1917 sourceConnectionProperties,
1918 SynchroDirection.IMPORT_SERVER2TEMP,
1919 userId,
1920 lastDataUpdateDate,
1921 enableDelete,
1922 true
1923 );
1924
1925 synchroContext.getTarget().putAllProperties(targetConnectionProperties);
1926 synchroContext.setDataStartDate(getTimestampOrNull(contextVO.getDataStartDate()));
1927 synchroContext.setDataEndDate(getTimestampOrNull(contextVO.getDataEndDate()));
1928 synchroContext.setPkIncludes(contextVO.getDataPkIncludes());
1929
1930 doImportData(synchroContext,
1931 t("quadrige2.service.synchro.import.data.message"),
1932 progressionModel,
1933 stepNumber,
1934 progressionModelStepCount);
1935
1936 return synchroContext;
1937 }
1938
1939 private SynchroContext doImportData(DataSynchroContext synchroContext,
1940 String progressionBaseMessage,
1941 ApplicationProgressionModel progressionModel,
1942 int progressionStepNumber,
1943 int progressionStepCount) {
1944 Preconditions.checkArgument(progressionStepNumber > 0);
1945 SynchroResult result = synchroContext.getResult();
1946
1947
1948 int progressionStepOffset = progressionStepCount * (progressionStepNumber - 1);
1949 addProgressionListeners(
1950 progressionBaseMessage,
1951 progressionModel,
1952 result.getProgressionModel(),
1953 progressionStepOffset,
1954 progressionStepCount);
1955
1956 dataSynchroService.prepare(synchroContext);
1957
1958 if (!result.isSuccess()) {
1959 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.prepare", result.getError()));
1960 }
1961
1962 dataSynchroService.synchronize(synchroContext);
1963
1964 if (!result.isSuccess()) {
1965 Exception error = result.getError();
1966
1967
1968 if (error instanceof DataIntegrityViolationOnDeleteException) {
1969 throw new Quadrige2BusinessException(t("quadrige2.error.synchro.import.synchro.delete",
1970 error.getMessage()));
1971 }
1972
1973 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.synchro"), error);
1974 }
1975
1976
1977 progressionModel.setCurrent(progressionStepOffset + progressionStepCount);
1978
1979 return synchroContext;
1980 }
1981
1982 private DataSynchroContext createContextAndExportDataToTempDb(Properties tempDbConnectionProperties,
1983 int userId,
1984 Set<String> programCodes,
1985 ApplicationProgressionModel progressionModel,
1986 int progressionStepNumber,
1987 int progressionStepCount) {
1988
1989 Properties localConnectionProperties = config.getConnectionProperties();
1990
1991
1992 DataSynchroContext context = dataSynchroService.createSynchroContext(localConnectionProperties,
1993 SynchroDirection.EXPORT_LOCAL2TEMP,
1994 userId,
1995 null,
1996 true,
1997 true );
1998 context.getTarget().putAllProperties(tempDbConnectionProperties);
1999 context.setProgramCodes(programCodes);
2000
2001 context = doExportData(context,
2002 t("quadrige2.synchro.progress.export"),
2003 progressionModel,
2004 progressionStepNumber,
2005 progressionStepCount);
2006
2007 return context;
2008 }
2009
2010 private ReferentialSynchroContext createContextAndExportProgramsToTempDb(Properties tempDbConnectionProperties,
2011 int userId,
2012 Set<String> programCodes,
2013 ApplicationProgressionModel progressionModel,
2014 int progressionStepNumber,
2015 int progressionStepCount) {
2016
2017 Properties localConnectionProperties = config.getConnectionProperties();
2018
2019
2020 ReferentialSynchroContext context = referentialSynchroService.createSynchroContext(localConnectionProperties,
2021 null,
2022 true,
2023 true ,
2024 SynchroDirection.EXPORT_LOCAL2TEMP,
2025 userId,
2026 null
2027 );
2028 context.getTarget().putAllProperties(tempDbConnectionProperties);
2029
2030
2031 context.setTableNames(ProgramStrategySynchroTables.tableNames());
2032
2033
2034 context.setProgramCodes(programCodes);
2035
2036 doExportReferential(context,
2037 t("quadrige2.synchro.progress.export"),
2038 progressionModel,
2039 progressionStepNumber,
2040 progressionStepCount);
2041
2042 return context;
2043 }
2044
2045 private DataSynchroContext createContextAndExportDataFromTempDbToServer(Properties tempDbConnectionProperties,
2046 int userId,
2047 ApplicationProgressionModel progressionModel,
2048 int progressionStepNumber,
2049 int progressionStepCount) {
2050
2051 Properties serverConnectionProperties = synchroConfig.getImportConnectionProperties();
2052
2053
2054 DataSynchroContext dataSynchroContext = dataSynchroService.createSynchroContext(tempDbConnectionProperties,
2055 SynchroDirection.EXPORT_TEMP2SERVER,
2056 userId,
2057 null,
2058 true ,
2059 true );
2060 dataSynchroContext.getTarget().putAllProperties(serverConnectionProperties);
2061
2062 dataSynchroContext = doExportData(dataSynchroContext,
2063 t("quadrige2.synchro.progress.export"),
2064 progressionModel,
2065 progressionStepNumber,
2066 progressionStepCount);
2067
2068 return dataSynchroContext;
2069 }
2070
2071 private DataSynchroContext doExportData(DataSynchroContext synchroContext,
2072 String progressionBaseMessage,
2073 ApplicationProgressionModel progressionModel,
2074 int progressionStepNumber,
2075 int progressionStepCount) {
2076
2077 Preconditions.checkArgument(progressionStepNumber > 0);
2078 SynchroResult result = synchroContext.getResult();
2079
2080
2081 int progressionStepOffset = progressionStepCount * (progressionStepNumber - 1);
2082 addProgressionListeners(
2083 progressionBaseMessage,
2084 progressionModel,
2085 result.getProgressionModel(),
2086 progressionStepOffset,
2087 progressionStepCount);
2088
2089 dataSynchroService.prepare(synchroContext);
2090
2091 if (!result.isSuccess()) {
2092 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.prepare"), result.getError());
2093 }
2094
2095 dataSynchroService.synchronize(synchroContext);
2096
2097 if (!result.isSuccess()) {
2098 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.synchro"), result.getError());
2099 }
2100
2101
2102 progressionModel.setCurrent(progressionStepOffset + progressionStepCount);
2103
2104 return synchroContext;
2105
2106 }
2107
2108 private void doExportReferential(
2109 ReferentialSynchroContext synchroContext,
2110 String progressionBaseMessage,
2111 ApplicationProgressionModel progressionModel,
2112 int progressionStepNumber,
2113 int progressionStepCount) {
2114 Preconditions.checkArgument(progressionStepNumber > 0);
2115
2116
2117 synchroContext.getSource().setIsMirrorDatabase(false);
2118
2119 synchroContext.getTarget().setIsMirrorDatabase(true);
2120 SynchroResult result = synchroContext.getResult();
2121
2122
2123 int progressionStepOffset = progressionStepCount * (progressionStepNumber - 1);
2124 addProgressionListeners(
2125 progressionBaseMessage,
2126 progressionModel,
2127 result.getProgressionModel(),
2128 progressionStepOffset,
2129 progressionStepCount);
2130
2131 referentialSynchroService.prepare(synchroContext);
2132
2133 if (!result.isSuccess()) {
2134 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.prepare"), result.getError());
2135 }
2136
2137 referentialSynchroService.synchronize(synchroContext);
2138
2139 if (!result.isSuccess()) {
2140 Exception error = result.getError();
2141
2142
2143 if (error instanceof DataIntegrityViolationOnDeleteException) {
2144 throw new Quadrige2BusinessException(t("quadrige2.error.synchro.export.synchro.delete",
2145 error.getMessage()));
2146 }
2147
2148 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.synchro"), error);
2149 }
2150
2151
2152 progressionModel.setCurrent(progressionStepOffset + progressionStepCount);
2153 }
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168 protected void addProgressionListeners(
2169 final String baseMessage,
2170 final ApplicationProgressionModel progressionModel,
2171 final ProgressionModel synchroProgressionModel,
2172 final int progressionModelOffset,
2173 final int progressionCount) {
2174
2175 synchroProgressionModel.addPropertyChangeListener(ProgressionModel.PROPERTY_CURRENT,
2176 new PropertyChangeListener() {
2177 @Override
2178 public void propertyChange(PropertyChangeEvent evt) {
2179 Integer current = (Integer) evt.getNewValue();
2180
2181 onProgressionCurrentChanged(progressionModel,
2182 current,
2183 synchroProgressionModel.getTotal(),
2184 progressionModelOffset,
2185 progressionCount);
2186 }
2187 });
2188
2189
2190 synchroProgressionModel.addPropertyChangeListener(ProgressionModel.PROPERTY_MESSAGE,
2191 new PropertyChangeListener() {
2192 @Override
2193 public void propertyChange(PropertyChangeEvent evt) {
2194 String message = (String) evt.getNewValue();
2195 progressionModel.setMessage(String.format(baseMessage, message));
2196 }
2197 });
2198 }
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216 protected void onProgressionCurrentChanged(ApplicationProgressionModel progressionModel,
2217 Integer current,
2218 Integer total,
2219 int progressionOffset,
2220 int progressionCount) {
2221
2222 if (current == null || total == null) {
2223 progressionModel.setCurrent(progressionOffset);
2224 return;
2225 }
2226 int progression = progressionOffset
2227 + Math.round(progressionCount * current / total);
2228 if (progression >= progressionOffset + progressionCount) {
2229 progression = progressionOffset + progressionCount - 2;
2230
2231 }
2232 progressionModel.setCurrent(progression);
2233 }
2234
2235 private DataSynchroContext createContextAndExportDataToFile(Properties tempDbConnectionProperties,
2236 int userId,
2237 Set<String> programCodes,
2238 boolean dirtyOnly, SynchroDateOperatorVO dateOperator, Date startDate, Date endDate,
2239 ApplicationProgressionModel progressionModel,
2240 int progressionStepNumber,
2241 int progressionStepCount) {
2242
2243 Properties localConnectionProperties = config.getConnectionProperties();
2244
2245
2246 DataSynchroContext context = dataSynchroService.createSynchroContext(localConnectionProperties,
2247 SynchroDirection.EXPORT_LOCAL2FILE,
2248 userId,
2249 null,
2250 true,
2251 true );
2252 context.getTarget().putAllProperties(tempDbConnectionProperties);
2253 context.setProgramCodes(programCodes);
2254 context.setDirtyOnly(dirtyOnly);
2255 context.setDataStartDate(startDate);
2256 context.setDataEndDate(endDate);
2257 context.setDateOperator(dateOperator);
2258
2259 context = doExportData(context,
2260 t("quadrige2.synchro.progress.export"),
2261 progressionModel,
2262 progressionStepNumber,
2263 progressionStepCount);
2264
2265 return context;
2266 }
2267
2268 private ReferentialSynchroContext createContextAndExportLocalReferential(int userId,
2269 Properties tempDbConnectionProperties,
2270 ApplicationProgressionModel progressionModel,
2271 int progressionStepNumber,
2272 int progressionStepCount) {
2273
2274 Properties localConnectionProperties = config.getConnectionProperties();
2275
2276
2277 ReferentialSynchroContext context = referentialSynchroService.createSynchroContext(localConnectionProperties,
2278 null,
2279 true,
2280 true ,
2281 SynchroDirection.EXPORT_LOCAL2FILE,
2282 userId,
2283
2284 Sets.newHashSet(StatusCode.LOCAL_ENABLE.getValue(),
2285 StatusCode.LOCAL_DISABLE.getValue())
2286 );
2287 context.getTarget().putAllProperties(tempDbConnectionProperties);
2288
2289
2290 {
2291 Set<String> tableNames = Sets.newHashSet(context.getTableNames());
2292
2293
2294 tableNames.removeAll(ProgramStrategySynchroTables.tableNames());
2295
2296
2297 tableNames.removeAll(CampaignOccasionSynchroTables.tableNames());
2298
2299
2300 tableNames.removeAll(RuleSynchroTables.tableNames());
2301
2302 context.setTableNames(tableNames);
2303 }
2304
2305
2306 doExportReferential(context,
2307 t("quadrige2.synchro.progress.export"),
2308 progressionModel,
2309 progressionStepNumber,
2310 progressionStepCount);
2311
2312 return context;
2313 }
2314
2315 private ReferentialSynchroContext createContextAndExportAdditionalReferentialToFile(int userId,
2316 Set<String> programCodes,
2317 Properties tempDbConnectionProperties,
2318 ApplicationProgressionModel progressionModel,
2319 int progressionStepNumber,
2320 int progressionStepCount) {
2321
2322 Properties localConnectionProperties = config.getConnectionProperties();
2323
2324
2325 ReferentialSynchroContext context = referentialSynchroService.createSynchroContext(localConnectionProperties,
2326 null,
2327 true,
2328 true ,
2329 SynchroDirection.EXPORT_LOCAL2FILE,
2330 userId,
2331
2332 null
2333 );
2334 context.getTarget().putAllProperties(tempDbConnectionProperties);
2335
2336
2337 if (CollectionUtils.isNotEmpty(programCodes)) {
2338 context.setProgramCodes(programCodes);
2339 }
2340
2341
2342 {
2343 Set<String> tableNames = Sets.newHashSet();
2344
2345
2346 tableNames.addAll(ProgramStrategySynchroTables.tableNames());
2347
2348
2349 tableNames.addAll(RuleSynchroTables.tableNames());
2350
2351
2352 tableNames.addAll(CampaignOccasionSynchroTables.tableNames());
2353
2354 context.setTableNames(tableNames);
2355 }
2356
2357
2358 doExportReferential(context,
2359 t("quadrige2.synchro.progress.export"),
2360 progressionModel,
2361 progressionStepNumber,
2362 progressionStepCount);
2363
2364 return context;
2365 }
2366
2367 private ReferentialSynchroContext createContextAndExportAllReferential(int userId,
2368 Properties tempDbConnectionProperties,
2369 ApplicationProgressionModel progressionModel,
2370 int progressionStepNumber,
2371 int progressionStepCount) {
2372
2373 Properties localConnectionProperties = config.getConnectionProperties();
2374
2375
2376 ReferentialSynchroContext context = referentialSynchroService.createSynchroContext(localConnectionProperties,
2377 null,
2378 true,
2379 true ,
2380 SynchroDirection.EXPORT_LOCAL2FILE,
2381 userId,
2382
2383 null
2384 );
2385 context.getTarget().putAllProperties(tempDbConnectionProperties);
2386
2387
2388
2389 context.getTarget().setIsMirrorDatabase(false);
2390
2391
2392 {
2393
2394 Set<String> tableNames = Sets.newHashSet(context.getTableNames());
2395
2396
2397 tableNames.addAll(RuleSynchroTables.tableNames());
2398
2399
2400 tableNames.addAll(ContextAndFilterSynchroTables.tableNames());
2401
2402
2403 tableNames.addAll(TechnicalSynchroTables.tableNames());
2404
2405 context.setTableNames(tableNames);
2406 }
2407
2408
2409 doExportReferential(context,
2410 t("quadrige2.synchro.progress.export"),
2411 progressionModel,
2412 progressionStepNumber,
2413 progressionStepCount);
2414
2415 return context;
2416 }
2417
2418 private Properties getConnectionPropertiesFromDbDirectory(File dbDirectory) {
2419 Properties dbConnectionProperties = new Properties();
2420 dbConnectionProperties.putAll(config.getConnectionProperties());
2421 dbConnectionProperties.setProperty(Environment.URL, Daos.getJdbcUrl(dbDirectory, config.getDbName()));
2422 return dbConnectionProperties;
2423 }
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434 protected Timestamp getTimestampOrNull(Date date) {
2435 return date == null ? null : new Timestamp(date.getTime());
2436 }
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451 protected <O> String decorate(O object, String name) {
2452 Decorator<O> decorator = decoratorService.getDecorator(object, name);
2453 Preconditions.checkNotNull(decorator);
2454 return decorator.toString(object);
2455 }
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468 protected <O> String decorate(O object) {
2469 Decorator<O> decorator = decoratorService.getDecorator(object);
2470 Preconditions.checkNotNull(decorator);
2471 return decorator.toString(object);
2472 }
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482 protected void shutdownDatabaseSilently(Properties connectionProperties) {
2483 try {
2484 Daos.shutdownDatabase(connectionProperties);
2485 } catch (Exception e1) {
2486
2487 log.warn(t("quadrige2.error.synchro.import.shutdown"));
2488 }
2489 }
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499 protected void deleteSilently(File dirToDelete) {
2500 try {
2501 FileUtils.forceDelete(dirToDelete);
2502 } catch (IOException e1) {
2503
2504 log.warn(String.format("Could not delete temp directory: %s", dirToDelete.getAbsolutePath()));
2505 }
2506 }
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517 protected Date getServerCurrentTimestamp(Properties serverConnectionProperties) {
2518 Connection connection = null;
2519
2520 try {
2521 connection = Daos.createConnection(serverConnectionProperties);
2522 Dialect dialect = Dialect.getDialect(serverConnectionProperties);
2523
2524 Date result = fr.ifremer.common.synchro.dao.Daos.getCurrentTimestamp(connection, dialect);
2525
2526 return result;
2527 } catch (SQLException e) {
2528 throw new Quadrige2TechnicalException(e);
2529 } finally {
2530 Daos.closeSilently(connection);
2531 }
2532 }
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544 protected void resolveRejectsAndFinishImportData(
2545 DataSynchroContext temp2LocalContext,
2546 SynchroRejectedRowResolver resolver
2547 ) {
2548 Preconditions.checkNotNull(temp2LocalContext);
2549
2550 Map<RejectedRow.Cause, RejectedRow.ResolveStrategy> rejectStrategies = Maps.newHashMap();
2551
2552
2553 Map<RejectedRow.Cause, String> rejectedRows = decorateRejectedRows(temp2LocalContext.getResult().getRejectedRows());
2554
2555
2556 RejectedRow.ResolveStrategy deletedRowStrategy = resolveRejects(rejectedRows, RejectedRow.Cause.BAD_UPDATE_DATE, resolver);
2557 rejectStrategies.put(RejectedRow.Cause.BAD_UPDATE_DATE, deletedRowStrategy);
2558
2559
2560 temp2LocalContext.setEnableDelete(true);
2561 temp2LocalContext.setEnableInsertOrUpdate(true);
2562 doFinishImportData(temp2LocalContext, rejectStrategies);
2563
2564 SynchroResult result = temp2LocalContext.getResult();
2565 if (!result.isSuccess()) {
2566 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.finish", result.getError()));
2567 }
2568 }
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580 protected void resolveFileRejectsAndFinishImportFromFile(
2581 DataSynchroContext file2LocalContext,
2582 SynchroRejectedRowResolver resolver
2583 ) {
2584 Preconditions.checkNotNull(file2LocalContext);
2585
2586 Map<RejectedRow.Cause, RejectedRow.ResolveStrategy> rejectStrategies = Maps.newHashMap();
2587
2588
2589 Map<RejectedRow.Cause, String> rejectedRows = decorateRejectedRows(file2LocalContext.getResult().getRejectedRows());
2590
2591
2592 RejectedRow.ResolveStrategy deletedRowStrategy = resolveRejects(rejectedRows, RejectedRow.Cause.BAD_UPDATE_DATE, resolver);
2593 rejectStrategies.put(RejectedRow.Cause.BAD_UPDATE_DATE, deletedRowStrategy);
2594
2595
2596 deletedRowStrategy = resolveRejects(rejectedRows, RejectedRow.Cause.DUPLICATE_KEY, resolver);
2597 rejectStrategies.put(RejectedRow.Cause.DUPLICATE_KEY, deletedRowStrategy);
2598
2599
2600 file2LocalContext.setEnableDelete(true);
2601 file2LocalContext.setEnableInsertOrUpdate(true);
2602 doFinishImportData(file2LocalContext, rejectStrategies);
2603
2604 SynchroResult result = file2LocalContext.getResult();
2605 if (!result.isSuccess()) {
2606 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.finish"), result.getError());
2607 }
2608 }
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619 protected Map<String, Map<String, Map<String, String>>> getReplaceValuesFromResult(
2620 SynchroResult synchroResult
2621 ) {
2622 Preconditions.checkNotNull(synchroResult);
2623
2624 if (MapUtils.isEmpty(synchroResult.getRejectedRows())) {
2625 return null;
2626 }
2627
2628 Map<String, Map<String, Map<String, String>>> allReplaceValues = Maps.newHashMap();
2629
2630 for (String tableName : synchroResult.getRejectedRows().keySet()) {
2631
2632 Map<String, Map<String, String>> replaceValuesByTable = Maps.newHashMap();
2633 allReplaceValues.put(tableName, replaceValuesByTable);
2634
2635 for (RejectedRow rejectedRow : RejectedRow.parseFromString(synchroResult.getRejectedRows().get(tableName))) {
2636
2637 }
2638 }
2639
2640 return allReplaceValues;
2641 }
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653 protected void resolveFileReferentialRejectsAndFinishImportFromFile(
2654 ReferentialSynchroContext file2LocalContext,
2655 SynchroRejectedRowResolver resolver
2656 ) {
2657 Preconditions.checkNotNull(file2LocalContext);
2658
2659 SynchroResult result = file2LocalContext.getResult();
2660
2661 Map<RejectedRow.Cause, RejectedRow.ResolveStrategy> rejectStrategies = Maps.newHashMap();
2662
2663
2664
2665
2666 Map<String, Map<String, String>> remapPks = file2LocalContext.getTarget().getRemapPks();
2667 if (MapUtils.isNotEmpty(remapPks)) {
2668 for (String tableName : remapPks.keySet()) {
2669 Map<String, String> tableRemapPks = remapPks.get(tableName);
2670 for (String sourcePkStr : tableRemapPks.keySet()) {
2671 String targetPkStr = tableRemapPks.get(sourcePkStr);
2672 addRejectForRemappedPkFromFile(result, tableName, sourcePkStr, targetPkStr);
2673 }
2674 }
2675 }
2676
2677
2678 Map<RejectedRow.Cause, String> rejectedRows = decorateRejectedRows(result.getRejectedRows());
2679
2680
2681 RejectedRow.ResolveStrategy deletedRowStrategy = resolveRejects(rejectedRows, RejectedRow.Cause.BAD_UPDATE_DATE, resolver);
2682 rejectStrategies.put(RejectedRow.Cause.BAD_UPDATE_DATE, deletedRowStrategy);
2683
2684
2685 deletedRowStrategy = resolveRejects(rejectedRows, RejectedRow.Cause.DUPLICATE_KEY, resolver);
2686 rejectStrategies.put(RejectedRow.Cause.DUPLICATE_KEY, deletedRowStrategy);
2687
2688
2689 file2LocalContext.setEnableDelete(true);
2690 file2LocalContext.setEnableInsertOrUpdate(true);
2691 doFinishImportReferential(file2LocalContext, rejectStrategies);
2692
2693 if (!result.isSuccess()) {
2694 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.referential.finish"), result.getError());
2695 }
2696 }
2697
2698 private void addRejectForRemappedPkFromFile(SynchroResult result, String tableName, String sourcePkStr, String targetPkStr) {
2699
2700
2701 result.addReject(tableName, sourcePkStr, RejectedRow.Cause.DUPLICATE_KEY.name(), targetPkStr, "REMAPPED_PK");
2702
2703
2704 if (ReferentialSynchroTables.TAXON_NAME.name().equalsIgnoreCase(tableName)) {
2705
2706 result.addReject(ReferentialSynchroTables.REFERENCE_TAXON.name(), sourcePkStr, RejectedRow.Cause.DUPLICATE_KEY.name(), targetPkStr,
2707 "REMAPPED_PK");
2708 }
2709 }
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724 protected RejectedRow.ResolveStrategy resolveRejects(
2725 Map<RejectedRow.Cause, String> rejectedRows,
2726 RejectedRow.Cause rejectedStatus,
2727 SynchroRejectedRowResolver resolver) {
2728
2729 RejectedRow.ResolveStrategy result = null;
2730
2731 if (rejectedRows.containsKey(rejectedStatus)) {
2732 String rejectMessage = rejectedRows.get(rejectedStatus);
2733
2734 result = resolver.resolveReject(rejectedStatus, null, rejectMessage);
2735 }
2736
2737 return result != null ? result : RejectedRow.ResolveStrategy.DO_NOTHING;
2738 }
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748 protected void doFinishImportData(
2749 DataSynchroContext temp2LocalContext,
2750 Map<RejectedRow.Cause, RejectedRow.ResolveStrategy> rejectStrategies) {
2751 Preconditions.checkNotNull(temp2LocalContext.getResult());
2752
2753
2754 SynchroResult result = temp2LocalContext.getResult();
2755
2756
2757 SynchroResult tempResult = new SynchroResult();
2758 temp2LocalContext.setResult(tempResult);
2759
2760 try {
2761
2762 SynchroDatabaseConfiguration tempDbConfiguration = temp2LocalContext.getSource();
2763 temp2LocalContext.setSource(null);
2764 dataSynchroService.finish(temp2LocalContext, result, rejectStrategies);
2765 if (!tempResult.isSuccess()) {
2766
2767 result.setError(tempResult.getError());
2768 return;
2769 }
2770
2771
2772
2773 result.getRejectedRows().clear();
2774 result.addAll(tempResult);
2775
2776
2777 Multimap<String, String> pksToRevert = ArrayListMultimap.create(result.getSourceMissingReverts());
2778 if (pksToRevert == null || pksToRevert.isEmpty()) {
2779
2780 return;
2781 }
2782
2783
2784
2785 temp2LocalContext.setPkIncludes(pksToRevert);
2786 temp2LocalContext.setForceEditedRowOverride(true);
2787 temp2LocalContext.setSource(tempDbConfiguration);
2788 tempResult.clear();
2789
2790 dataSynchroService.prepare(temp2LocalContext);
2791
2792 if (!tempResult.isSuccess()) {
2793 result.setError(tempResult.getError());
2794 return;
2795 }
2796
2797 dataSynchroService.synchronize(temp2LocalContext);
2798
2799
2800 result.getSourceMissingReverts().clear();
2801 result.addAll(tempResult);
2802
2803 if (!tempResult.isSuccess()) {
2804 result.setError(tempResult.getError());
2805 return;
2806 }
2807
2808 }
2809
2810
2811 finally {
2812 temp2LocalContext.setResult(result);
2813 }
2814 }
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824 protected void doFinishImportReferential(
2825 ReferentialSynchroContext temp2LocalContext,
2826 Map<RejectedRow.Cause, RejectedRow.ResolveStrategy> rejectStrategies) {
2827 Preconditions.checkNotNull(temp2LocalContext.getResult());
2828
2829
2830 SynchroResult result = temp2LocalContext.getResult();
2831
2832
2833 SynchroResult tempResult = new SynchroResult();
2834 temp2LocalContext.setResult(tempResult);
2835
2836 SynchroDatabaseConfiguration tempDbConfiguration = temp2LocalContext.getSource();
2837 try {
2838
2839 temp2LocalContext.setSource(null);
2840 referentialSynchroService.finish(temp2LocalContext, result, rejectStrategies);
2841 if (!tempResult.isSuccess()) {
2842
2843 result.setError(tempResult.getError());
2844 return;
2845 }
2846
2847
2848
2849 result.getRejectedRows().clear();
2850 result.addAll(tempResult);
2851 }
2852
2853
2854 finally {
2855 temp2LocalContext.setSource(tempDbConfiguration);
2856 temp2LocalContext.setResult(result);
2857 }
2858 }
2859
2860 private Map<RejectedRow.Cause, String> decorateRejectedRows(Map<String, String> rejectedRows) {
2861
2862 Map<RejectedRow.Cause, StringBuilder> result = Maps.newHashMap();
2863
2864 if (CollectionUtils.isEmpty(rejectedRows.keySet())) {
2865 return Maps.newHashMap();
2866 }
2867
2868 for (String tableName : rejectedRows.keySet()) {
2869 for (RejectedRow reject : RejectedRow.parseFromString(rejectedRows.get(tableName))) {
2870
2871 String remotePkStr = reject.pkStr;
2872 String pkStr;
2873 if (StringUtils.isNotBlank(reject.targetPkStr)) {
2874 pkStr = reject.targetPkStr;
2875 }
2876 else {
2877 pkStr = remotePkStr;
2878 }
2879
2880
2881 StringBuilder sb = result.get(reject.cause);
2882 if (sb == null) {
2883 sb = new StringBuilder();
2884 result.put(reject.cause, sb);
2885 }
2886
2887
2888 try {
2889 switch (tableName.toUpperCase()) {
2890 case TABLE_SURVEY: {
2891 Integer id = Integer.valueOf(pkStr);
2892 LightSurveyVO survey = surveyDao.getLightSurveyById(id);
2893 sb.append(decorate(survey));
2894 }
2895 break;
2896 default: {
2897 sb.append(t("quadrige2.service.synchro.rejection.object", tableName, pkStr));
2898 }
2899 }
2900 } catch (Exception e) {
2901 log.error("unable to get the object", e);
2902 sb.append(t("quadrige2.service.synchro.rejection.object", tableName, pkStr));
2903 }
2904
2905
2906 if (reject.validUpdateDate != null) {
2907 sb.append(' ');
2908 sb.append(t("quadrige2.service.synchro.rejection.BAD_UPDATE_DATE.updateDate", reject.validUpdateDate.toString()));
2909 }
2910 sb.append('\n');
2911
2912 }
2913 }
2914
2915 return Maps.transformValues(result, new Function<StringBuilder, String>() {
2916
2917 @Override
2918 public String apply(StringBuilder input) {
2919 return input.toString();
2920 }
2921 });
2922 }
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934 private Date computeDataSynchronizationDate(Map<String, String> rejectedRows,
2935 Date synchroDate,
2936 Date previousSynchroDate) {
2937
2938 if (MapUtils.isEmpty(rejectedRows)) {
2939 return synchroDate;
2940 } else {
2941 long minUpdateDate = synchroDate.getTime();
2942 for (String tableName : rejectedRows.keySet()) {
2943 for (RejectedRow rejectRow : RejectedRow.parseFromString(rejectedRows.get(tableName))) {
2944 if (rejectRow.cause == RejectedRow.Cause.BAD_UPDATE_DATE) {
2945 Timestamp rowUpdateDate = rejectRow.validUpdateDate;
2946 if (rowUpdateDate != null && rowUpdateDate.getTime() < minUpdateDate) {
2947
2948 minUpdateDate = rowUpdateDate.getTime() - 1000;
2949 }
2950 } else {
2951
2952
2953 log.warn(String.format("Data synchronization date not udpated: rejected rows (other than %s) detected on import: %s",
2954 RejectedRow.Cause.BAD_UPDATE_DATE,
2955 rejectRow));
2956 return previousSynchroDate;
2957 }
2958 }
2959 }
2960
2961 return new Date(minUpdateDate);
2962 }
2963 }
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974 public File getSynchroDirectoryByUser(int userId) {
2975 File result = new File(
2976 config.getSynchronizationDirectory(),
2977 new StringBuilder()
2978 .append(userId)
2979 .toString());
2980 return result;
2981 }
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991 protected void checkValidImportFile(File file) {
2992 if (!file.exists()) {
2993 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.file.notExists", file.getPath()));
2994 }
2995
2996 if (!ZipUtil.isZipFile(file)) {
2997 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.import.file.notZipFile", file.getPath()));
2998 }
2999 }
3000
3001 private DataSynchroContext createContextAndImportFromFile(int userId,
3002 File dbDirToImport,
3003 Multimap<String, String> pkToIncludes,
3004 Map<String, Map<String, Map<String, Object>>> remapValues,
3005 boolean forceDuplication,
3006 ApplicationProgressionModel progressionModel,
3007 int stepNumber,
3008 int progressionModelStepCount) {
3009 return createContextAndImportFromFile(userId,
3010 dbDirToImport,
3011 null,
3012 false,
3013 pkToIncludes,
3014 remapValues,
3015 forceDuplication,
3016 t("quadrige2.service.synchro.import.data.message"),
3017 progressionModel,
3018 stepNumber,
3019 progressionModelStepCount);
3020 }
3021
3022 private DataSynchroContext createContextAndImportFromFile(int userId,
3023 File dbDirToImport,
3024 File changeLogFile,
3025 boolean rollbackOnly,
3026 Multimap<String, String> pkToIncludes,
3027 Map<String, Map<String, Map<String, Object>>> remapValues,
3028 boolean forceDuplication,
3029 String progressionBaseMessage,
3030 ApplicationProgressionModel progressionModel,
3031 int stepNumber,
3032 int progressionModelStepCount) {
3033
3034 DataSynchroContext synchroContext = dataSynchroService.createSynchroContext(
3035 dbDirToImport,
3036 SynchroDirection.IMPORT_FILE2LOCAL,
3037 userId,
3038 null ,
3039 false ,
3040 true
3041 );
3042
3043
3044 synchroContext.setChangeLogFile(changeLogFile);
3045
3046
3047 synchroContext.setPkIncludes(pkToIncludes);
3048
3049
3050 synchroContext.setRemapValues(remapValues);
3051
3052
3053 synchroContext.setForceDuplication(forceDuplication);
3054
3055
3056 synchroContext.getTarget().setRollbackOnly(rollbackOnly);
3057
3058
3059 synchroContext.setForceEditedRowOverride(false);
3060
3061 doImportData(synchroContext,
3062 progressionBaseMessage,
3063 progressionModel,
3064 stepNumber,
3065 progressionModelStepCount);
3066
3067 return synchroContext;
3068 }
3069
3070 private void finishExportDataToFile(SynchroClientExportToFileResult exportResult) {
3071 Preconditions.checkNotNull(exportResult.getDataResult());
3072
3073
3074 SynchroResult result = exportResult.getDataResult();
3075 DataSynchroContext dataSynchroContext = exportResult.getDataContext();
3076 SynchroDatabaseConfiguration target = dataSynchroContext.getTarget();
3077 dataSynchroContext.setTarget(dataSynchroContext.getSource());
3078 dataSynchroContext.setSource(null);
3079
3080
3081 try {
3082 SynchroResult tempResult = new SynchroResult();
3083 dataSynchroContext.setResult(tempResult);
3084
3085
3086
3087 Map<RejectedRow.Cause, RejectedRow.ResolveStrategy> rejectedRowStrategy =
3088 ImmutableMap.<RejectedRow.Cause, RejectedRow.ResolveStrategy> builder()
3089 .put(RejectedRow.Cause.DUPLICATE_KEY, RejectedRow.ResolveStrategy.DO_NOTHING)
3090 .put(RejectedRow.Cause.DELETED, RejectedRow.ResolveStrategy.DO_NOTHING)
3091 .put(RejectedRow.Cause.BAD_UPDATE_DATE, RejectedRow.ResolveStrategy.DO_NOTHING)
3092 .build();
3093 dataSynchroService.finish(dataSynchroContext, result, rejectedRowStrategy);
3094
3095 if (!tempResult.isSuccess()) {
3096
3097 result.setError(tempResult.getError());
3098 throw new Quadrige2TechnicalException(t("quadrige2.error.synchro.export.finish"), tempResult.getError());
3099 }
3100
3101
3102 result.getRejectedRows().clear();
3103 result.getSourceMissingUpdates().clear();
3104 result.getSourceMissingDeletes().clear();
3105 result.getRejectedRows().putAll(tempResult.getRejectedRows());
3106
3107 } finally {
3108
3109 dataSynchroContext.setResult(result);
3110 dataSynchroContext.setSource(dataSynchroContext.getTarget());
3111 dataSynchroContext.setTarget(target);
3112 }
3113 }
3114
3115
3116
3117
3118
3119
3120
3121
3122 protected DecoratorService getDecoratorService() {
3123 return decoratorService;
3124 }
3125
3126
3127
3128
3129
3130
3131
3132
3133 protected Quadrige2Configuration getConfig() {
3134 return config;
3135 }
3136
3137
3138
3139
3140
3141
3142
3143
3144 protected SynchroRejectedRowResolver newReferentialSynchroRejectedRowResolver() {
3145
3146 return new SynchroRejectedRowResolver() {
3147 @Override
3148 public void showRejectMessage(Map<RejectedRow.Cause, String> rejectedRowsByCause, RejectedRow.Cause causeFilter, boolean failMessage) {
3149
3150 }
3151
3152 @Override
3153 public RejectedRow.ResolveStrategy resolveReject(RejectedRow.Cause rejectCause, String rejectInfos, String rejectMessage) {
3154 if (rejectCause == RejectedRow.Cause.DUPLICATE_KEY) {
3155 return RejectedRow.ResolveStrategy.KEEP_LOCAL;
3156 }
3157 return RejectedRow.ResolveStrategy.DO_NOTHING;
3158 }
3159 };
3160 }
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171 protected Map<String, Map<String, Map<String, Object>>> getDataRemapValuesFromReferentialResult(SynchroResult referentialResult) {
3172 if (referentialResult == null || MapUtils.isEmpty(referentialResult.getSourceMissingUpdates())) {
3173 return null;
3174 }
3175
3176 final Set<String> dataTableIncludes = DataSynchroTables.getImportTablesIncludes();
3177
3178
3179 Map<String, Map<String, Map<String, Object>>> result = Maps.filterKeys(referentialResult.getSourceMissingUpdates(),
3180 new Predicate<String>() {
3181 @Override
3182 public boolean apply(@Nullable String tableName) {
3183 return dataTableIncludes.contains(tableName);
3184 }
3185 });
3186
3187 return result;
3188 }
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198 private void handleDeleteException(DataIntegrityViolationOnDeleteException deleteException, SynchroDatabaseConfiguration target) {
3199
3200 String tableName = deleteException.getTableName();
3201 String pkStr = deleteException.getPkStr();
3202 String i18nTableName = decorate(tableName, DecoratorService.TABLE_NAME);
3203
3204 String i18nRow = null;
3205
3206 if (StringUtils.isNoneBlank(tableName) && StringUtils.isNoneBlank(pkStr) && SynchroTableMetadata.fromPkStr(pkStr).size() == 1) {
3207 ReferentialJdbcDao referentialJdbcDao = new ReferentialJdbcDaoImpl(target.getConnectionProperties());
3208 try {
3209 Object entity = referentialJdbcDao.getVOByTableNameAndPk(deleteException.getTableName(), pkStr);
3210 if (entity != null) {
3211 i18nRow = decorate(entity);
3212 if (StringUtils.isBlank(tableName)) {
3213 i18nRow = String.format("%s (pk=%s)", tableName, pkStr);
3214 }
3215 }
3216 } catch (Quadrige2TechnicalException e) {
3217
3218 i18nRow = null;
3219 }
3220 }
3221
3222
3223 if (i18nTableName != null && i18nRow != null) {
3224 throw new Quadrige2BusinessException(t("quadrige2.error.synchro.import.synchro.delete.details",
3225 i18nTableName,
3226 i18nRow),
3227 deleteException);
3228 } else {
3229 throw new Quadrige2BusinessException(t("quadrige2.error.synchro.import.synchro.delete",
3230 deleteException.getMessage()));
3231 }
3232
3233 }
3234
3235
3236
3237
3238
3239
3240
3241 private void inverseRejectsSourceAndTargetPks(SynchroResult result) {
3242
3243 Map<String, String> rejectedRows = result.getRejectedRows();
3244
3245 Map<String, String> inversedRejectedRows = Maps.newTreeMap();
3246
3247 if (CollectionUtils.isNotEmpty(rejectedRows.keySet())) {
3248
3249 for (String tableName : rejectedRows.keySet()) {
3250
3251 String rejectLines = rejectedRows.get(tableName);
3252
3253
3254 for (RejectedRow rejectedRow : RejectedRow.parseFromString(rejectLines)) {
3255 if (rejectedRow.targetPkStr == null) {
3256 throw new Quadrige2TechnicalException(String.format(
3257 "Invalid reject data [%s]: missing 'targetPkStr'. Could process this reject.", rejectLines));
3258 }
3259
3260 rejectedRow.inverse();
3261
3262 RejectedRow.appendAsString(inversedRejectedRows, tableName, rejectedRow.toString());
3263 }
3264 }
3265 }
3266
3267 rejectedRows.clear();
3268 rejectedRows.putAll(inversedRejectedRows);
3269 }
3270
3271 }