1 package fr.ifremer.quadrige3.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.gson.reflect.TypeToken;
27 import fr.ifremer.common.synchro.service.SynchroResult;
28 import fr.ifremer.quadrige3.core.ProgressionCoreModel;
29 import fr.ifremer.quadrige3.core.config.QuadrigeConfiguration;
30 import fr.ifremer.quadrige3.core.dao.technical.Assert;
31 import fr.ifremer.quadrige3.core.dao.technical.Files;
32 import fr.ifremer.quadrige3.core.dao.technical.gson.Gsons;
33 import fr.ifremer.quadrige3.core.exception.*;
34 import fr.ifremer.quadrige3.core.security.AuthenticationInfo;
35 import fr.ifremer.quadrige3.core.service.http.HttpService;
36 import fr.ifremer.quadrige3.core.vo.administration.program.ProgramVO;
37 import fr.ifremer.quadrige3.core.vo.administration.user.QuserVO;
38 import fr.ifremer.quadrige3.core.vo.data.survey.CampaignVO;
39 import fr.ifremer.quadrige3.core.vo.system.generalCondition.GeneralConditionVO;
40 import fr.ifremer.quadrige3.core.vo.system.rule.RuleListVO;
41 import fr.ifremer.quadrige3.synchro.vo.SynchroExportContextVO;
42 import fr.ifremer.quadrige3.synchro.vo.SynchroImportContextVO;
43 import fr.ifremer.quadrige3.synchro.vo.SynchroProgressionStatus;
44 import fr.ifremer.quadrige3.synchro.vo.SynchroProgressionVO;
45 import org.apache.commons.collections4.CollectionUtils;
46 import org.apache.commons.io.FileUtils;
47 import org.apache.commons.io.FilenameUtils;
48 import org.apache.commons.lang3.StringUtils;
49 import org.apache.commons.lang3.time.DateUtils;
50 import org.apache.commons.logging.Log;
51 import org.apache.commons.logging.LogFactory;
52 import org.apache.http.client.methods.HttpGet;
53 import org.apache.http.client.methods.HttpPost;
54 import org.apache.http.entity.ContentType;
55 import org.apache.http.entity.StringEntity;
56 import org.nuiton.i18n.I18n;
57 import org.nuiton.version.Version;
58 import org.nuiton.version.Versions;
59 import org.springframework.context.annotation.Lazy;
60 import org.springframework.stereotype.Service;
61
62 import javax.annotation.Resource;
63 import java.io.File;
64 import java.io.IOException;
65 import java.lang.reflect.Type;
66 import java.nio.file.Path;
67 import java.util.*;
68
69 import static org.nuiton.i18n.I18n.t;
70
71
72
73
74
75
76 @Service("synchroRestClientService")
77 @Lazy
78 public class SynchroRestClientServiceImpl implements SynchroRestClientService {
79
80 private static final Log log = LogFactory.getLog(SynchroRestClientServiceImpl.class);
81
82 private static final String URL_USER_CURRENT = "/service/user/current";
83 private static final String URL_USER_READABLE_PROGRAMS = "/service/user/readablePrograms";
84 private static final String URL_USER_WRITABLE_PROGRAMS = "/service/user/writablePrograms";
85 private static final String URL_PROGRAM_GET = "/service/program/get/%s";
86 private static final String URL_PROGRAM_COMPATIBLE_CODES = "/service/program/compatibleProgramCodes";
87 private final static String URL_CHECK_VERSION = "/service/version/check/%s";
88 private final static String URL_GET_VERSION = "/service/version/get";
89 private final static String URL_IMPORT_CHECK_ANONYMOUSLY = "/service/import/check/anonymous";
90 private final static String URL_IMPORT_CHECK = "/service/import/check";
91 private final static String URL_IMPORT_CHECK_DATA = "/service/import/check/data";
92 private final static String URL_IMPORT_STATUS = "/service/import/status/%s";
93 private final static String URL_IMPORT_START = "/service/import/start";
94 private final static String URL_IMPORT_START_ANONYMOUSLY = "/service/import/start/anonymous";
95 private final static String URL_IMPORT_STOP = "/service/import/stop/%s";
96 private final static String URL_IMPORT_ACKNOWLEDGE = "/service/import/acknowledge";
97 private static final String URL_IMPORT_REFERENTIAL_UPDATE_DATE = "/service/import/referential/updateDate";
98 private static final String URL_IMPORT_REFERENTIAL_UPDATE_DATE_CLEAR_CACHE = "/service/import/referential/updateDate/clear";
99 private static final String URL_IMPORT_PHOTO = "/service/import/photo/%s";
100 private static final String URL_EXPORT_UPLOAD = "/service/export/upload";
101 private final static String URL_EXPORT_STATUS = "/service/export/status/%s";
102 private final static String URL_EXPORT_START = "/service/export/start";
103 private final static String URL_EXPORT_STOP = "/service/export/stop/%s";
104 private final static String URL_EXPORT_FILES = "/service/export/files/%s";
105 private static final String URL_EXPORT_ACKNOWLEDGE = "/service/export/acknowledge";
106 private static final String URL_PROGRAM_SAVE_LIST = "/service/program/save/list/";
107 private static final String URL_CAMPAIGN_SAVE_LIST = "/service/campaign/save/list/";
108 private static final String URL_CAMPAIGN_DELETE_LIST = "/service/campaign/delete/list/";
109 private static final String URL_RULE_LIST_SAVE_LIST = "/service/ruleList/save/list/";
110 private static final String URL_RULE_LIST_DELETE_LIST = "/service/ruleList/delete/list/";
111 private static final String URL_RULE_LIST_GET = "/service/ruleList/get/%s";
112 private static final String URL_GENERAL_CONDITION_GET = "/service/generalCondition/lastNonAccepted";
113 private static final String URL_GENERAL_CONDITION_ACCEPT = "/service/generalCondition/accept";
114
115 @Resource
116 private QuadrigeConfiguration configuration;
117
118 @Resource(name = "httpService")
119 private HttpService httpService;
120
121
122
123
124 @Override
125 public QuserVO getUser(AuthenticationInfo authenticationInfo) {
126
127 QuserVO result;
128
129 if (log.isDebugEnabled()) {
130 log.debug(String.format("Try to retrieve authenticated user data, from the synchronization server [%s]", configuration.getSynchronizationSiteUrl()));
131 }
132
133 try {
134 HttpGet request = new HttpGet(httpService.getPathUri(URL_USER_CURRENT));
135 result = httpService.executeRequest(authenticationInfo, request, QuserVO.class);
136 } catch (QuadrigeTechnicalException e) {
137 log.error(I18n.t("quadrige3.error.remote.currentPerson.failed", e.getMessage()), e);
138 throw e;
139 }
140
141 return result;
142 }
143
144 @Override
145 public List<ProgramVO> getReadableProgramsForUser(AuthenticationInfo authenticationInfo) throws QuadrigeTechnicalException {
146 List<ProgramVO> result;
147
148 if (log.isDebugEnabled()) {
149 log.debug(String.format("Try to retrieve readable programs of authenticated user, from the synchronization server [%s]", configuration.getSynchronizationSiteUrl()));
150 }
151
152 try {
153 HttpGet request = new HttpGet(httpService.getPathUri(URL_USER_READABLE_PROGRAMS));
154 Type listType = new TypeToken<ArrayList<ProgramVO>>() {
155 }.getType();
156 result = httpService.executeRequest(authenticationInfo, request, listType);
157 } catch (QuadrigeTechnicalException e) {
158 log.error(I18n.t("quadrige3.error.remote.programs.get.failed", e.getMessage()), e);
159 throw e;
160 }
161 return result;
162 }
163
164
165
166
167 @Override
168 public List<ProgramVO> getWritableProgramsForUser(AuthenticationInfo authenticationInfo) {
169
170 List<ProgramVO> result;
171
172 if (log.isDebugEnabled()) {
173 log.debug(String.format("Try to retrieve writable programs of authenticated user, from the synchronization server [%s]", configuration.getSynchronizationSiteUrl()));
174 }
175
176 try {
177 HttpGet request = new HttpGet(httpService.getPathUri(URL_USER_WRITABLE_PROGRAMS));
178 Type listType = new TypeToken<ArrayList<ProgramVO>>() {
179 }.getType();
180 result = httpService.executeRequest(authenticationInfo, request, listType);
181 } catch (QuadrigeTechnicalException e) {
182 log.error(I18n.t("quadrige3.error.remote.programs.get.failed", e.getMessage()), e);
183 throw e;
184 }
185 return result;
186 }
187
188 @Override
189 public Set<String> getCompatibleProgramCodes(AuthenticationInfo authenticationInfo) throws QuadrigeTechnicalException {
190 Set<String> result;
191
192 if (log.isDebugEnabled()) {
193 log.debug(String.format("Try to retrieve compatible programs from the synchronization server [%s]", configuration.getSynchronizationSiteUrl()));
194 }
195
196 try {
197 HttpGet request = new HttpGet(httpService.getPathUri(URL_PROGRAM_COMPATIBLE_CODES));
198 Type listType = new TypeToken<LinkedHashSet<String>>() {
199 }.getType();
200 result = httpService.executeRequest(authenticationInfo, request, listType);
201 } catch (QuadrigeTechnicalException e) {
202 log.error(I18n.t("quadrige3.error.remote.programs.compatible.get.failed", e.getMessage()), e);
203 throw e;
204 }
205 return result;
206 }
207
208
209
210
211 @Override
212 public ProgramVO getProgramByCode(AuthenticationInfo authenticationInfo, String progCd) {
213 Assert.notNull(progCd);
214
215 if (log.isDebugEnabled()) {
216 log.debug(String.format("Try to retrieve program [%s], from the synchronization server [%s]", progCd, configuration.getSynchronizationSiteUrl()));
217 }
218
219 try {
220 HttpGet request = new HttpGet(httpService.getPathUri(String.format(URL_PROGRAM_GET, progCd)));
221 return httpService.executeRequest(authenticationInfo, request, ProgramVO.class);
222 } catch (QuadrigeTechnicalException e) {
223 log.error(I18n.t("quadrige3.error.remote.program.get.failed", progCd, e.getMessage()), e);
224 throw e;
225 }
226 }
227
228
229
230
231 @Override
232 public SynchroImportContextVO checkImportContext(AuthenticationInfo authenticationInfo, SynchroImportContextVO importContextVO) {
233 if (log.isDebugEnabled()) {
234 log.debug(String.format("Check if exists referential updates on the synchronization server [%s]", configuration.getSynchronizationSiteUrl()));
235 }
236
237 if (CollectionUtils.isEmpty(importContextVO.getReferentialProgramCodes())) {
238
239 Set<String> programCodes = configuration.getSynchroProgramCodeIncludes();
240 if (CollectionUtils.isNotEmpty(programCodes)) {
241 importContextVO.setReferentialProgramCodes(programCodes);
242 }
243 }
244
245
246
247 if (!importContextVO.isWithData() && !importContextVO.isWithReferential()) {
248 importContextVO.setWithReferential(true);
249 }
250
251 boolean isAnonymous = authenticationInfo == null;
252
253 try {
254
255 checkVersion(authenticationInfo);
256
257
258 HttpPost request = createHttpPostWithStringEntity(isAnonymous ? URL_IMPORT_CHECK_ANONYMOUSLY : URL_IMPORT_CHECK, importContextVO);
259
260
261 return httpService.executeRequest(authenticationInfo, request, SynchroImportContextVO.class);
262
263 } catch (QuadrigeTechnicalException e) {
264 log.error(I18n.t("quadrige3.error.remote.checkImportContext.failed", e.getMessage()), e);
265 throw e;
266 }
267 }
268
269 @Override
270 public SynchroImportContextVO checkImportDataContext(AuthenticationInfo authenticationInfo, SynchroImportContextVO importContextVO) throws QuadrigeTechnicalException {
271 if (log.isDebugEnabled()) {
272 log.debug(String.format("Check if exists data updates on the synchronization server [%s]", configuration.getSynchronizationSiteUrl()));
273 }
274
275
276 importContextVO.setWithData(true);
277
278 try {
279
280 checkVersion(authenticationInfo);
281
282
283 HttpPost request = createHttpPostWithStringEntity(URL_IMPORT_CHECK_DATA, importContextVO);
284
285
286 return httpService.executeRequest(authenticationInfo, request, SynchroImportContextVO.class);
287 } catch (QuadrigeTechnicalException e) {
288 log.error(I18n.t("quadrige3.error.remote.checkImportContext.failed", e.getMessage()), e);
289 throw e;
290 }
291 }
292
293
294
295
296
297
298 @Override
299 public void checkVersion(AuthenticationInfo authenticationInfo) {
300
301
302 Version localVersionToCheck = QuadrigeConfiguration.getInstance().getVersion();
303
304 if (log.isDebugEnabled()) {
305 log.debug(String.format("Checking if version [%s] is compatible with the synchronization server [%s]", localVersionToCheck.getVersion(),
306 configuration.getSynchronizationSiteUrl()));
307 }
308
309
310 HttpGet request = new HttpGet(httpService.getPathUri(String.format(URL_CHECK_VERSION, localVersionToCheck.getVersion())));
311 String isVersionAllowedStr = httpService.executeRequest(authenticationInfo, request, String.class);
312 boolean isVersionAllowed = Boolean.valueOf(isVersionAllowedStr);
313
314
315 if (!isVersionAllowed) {
316
317
318 request = new HttpGet(httpService.getPathUri(URL_GET_VERSION));
319 String serverVersionStr = httpService.executeRequest(authenticationInfo, request, String.class);
320 Version serverVersion = null;
321 if (StringUtils.isNotBlank(serverVersionStr)) {
322 serverVersion = Versions.valueOf(serverVersionStr.replaceAll("\"", ""));
323 }
324
325
326 throw new QuadrigeBusinessException(I18n.t("quadrige3.error.synchro.version", localVersionToCheck, serverVersion));
327 }
328 }
329
330
331
332
333 @Override
334 public SynchroProgressionVO startImport(AuthenticationInfo authenticationInfo,
335 SynchroImportContextVO importContextVO,
336 ProgressionCoreModel progressionModel) {
337 Assert.notNull(importContextVO);
338
339 String jobId = importContextVO.getJobId();
340 boolean previouslyLaunched = jobId != null;
341
342 boolean isAnonymous = authenticationInfo == null;
343
344 try {
345 progressionModel.setMessage(t("quadrige3.synchro.progress.start"));
346
347
348 checkVersion(authenticationInfo);
349
350 if (!previouslyLaunched) {
351
352 HttpPost request = createHttpPostWithStringEntity(isAnonymous ? URL_IMPORT_START_ANONYMOUSLY : URL_IMPORT_START, importContextVO);
353
354
355 SynchroImportContextVO resultImportContextVO = httpService.executeRequest(authenticationInfo, request, SynchroImportContextVO.class);
356 jobId = resultImportContextVO.getJobId();
357
358
359 importContextVO.setJobId(jobId);
360 }
361
362
363 Thread.sleep(50);
364
365 return getImportLastStatus(authenticationInfo, jobId, progressionModel);
366
367 } catch (QuadrigeTechnicalException e) {
368 log.error(I18n.t("quadrige3.error.remote.startImport.failed", e.getMessage()), e);
369 throw e;
370 } catch (Exception e) {
371 log.error(I18n.t("quadrige3.error.remote.startImport.failed", e.getMessage()), e);
372 throw new QuadrigeTechnicalException(e);
373 }
374 }
375
376
377
378
379 @Override
380 public void stopImport(AuthenticationInfo authenticationInfo, String importJobId) {
381 if (log.isDebugEnabled()) {
382 log.debug(String.format("try to stop synchronization job [%s] on servers", importJobId));
383 }
384
385
386 HttpGet request = new HttpGet(httpService.getPathUri(String.format(URL_IMPORT_STOP, importJobId)));
387
388
389 httpService.executeRequest(authenticationInfo, request);
390
391 }
392
393
394
395
396 @Override
397 public void acknowledgeImport(AuthenticationInfo authenticationInfo, SynchroImportContextVO importContextVO) throws QuadrigeTechnicalException {
398
399 if (log.isDebugEnabled()) {
400 log.debug(String.format("Sending import acknowledge to the synchronization server [%s]", configuration.getSynchronizationSiteUrl()));
401 }
402
403
404 if (importContextVO.getReferentialUpdateDate() != null) {
405 importContextVO = (SynchroImportContextVO) importContextVO.clone();
406 importContextVO.setReferentialUpdateDate(DateUtils.addSeconds(importContextVO.getReferentialUpdateDate(), configuration.getImportReferentialUpdateDateOffsetInSecond()));
407 }
408
409 try {
410
411
412 HttpPost request = createHttpPostWithStringEntity(URL_IMPORT_ACKNOWLEDGE, importContextVO);
413
414
415 httpService.executeRequest(authenticationInfo, request);
416
417 } catch (QuadrigeTechnicalException e) {
418 log.error(I18n.t("quadrige3.error.remote.acknowledgeImport.failed", e.getMessage()), e);
419
420 }
421 }
422
423
424
425
426 @Override
427 public void uploadExportFile(AuthenticationInfo authenticationInfo, File fileToUpload, ProgressionCoreModel progressionModel)
428 throws QuadrigeTechnicalException {
429
430 if (!fileToUpload.exists()) {
431 throw new QuadrigeBusinessException(I18n.t("quadrige3.error.file.not.exists", fileToUpload.getAbsolutePath()));
432 }
433
434
435 long fileSize = fileToUpload.length();
436 if (fileSize == 0L) {
437 throw new QuadrigeBusinessException(I18n.t("quadrige3.error.file.size.invalid", fileToUpload.getAbsolutePath()));
438 }
439 long maxUploadSize = configuration.getExportDataFileMaxUploadSize();
440
441 if (log.isDebugEnabled()) {
442 log.debug(String.format("file to transfer to server: %s", fileToUpload.getAbsolutePath()));
443 if (fileSize > maxUploadSize)
444 log.debug(String.format("file will be split : file size is %s and configured max upload size is %s", fileSize, maxUploadSize));
445 }
446
447 List<Path> filesToUpload;
448 String progressionMessage = progressionModel.getMessage();
449 try {
450
451
452 filesToUpload = Files.splitFile(fileToUpload.toPath(), maxUploadSize - 1000);
453 } catch (IOException e) {
454 log.error(I18n.t("quadrige3.error.file.split.failed", e.getMessage()), e);
455 throw new QuadrigeTechnicalException(e);
456 }
457 boolean multipleFiles = filesToUpload.size() > 1;
458
459 try {
460 int nFile = 0;
461
462 for (Path file : filesToUpload) {
463
464 if (multipleFiles)
465 progressionModel.setMessage(String.format("%s (%s/%s)", progressionMessage, ++nFile, filesToUpload.size()));
466
467
468 HttpPost uploadHttpPost = new HttpPost(httpService.getPathUri(URL_EXPORT_UPLOAD));
469
470
471 httpService.executeUploadFileRequest(authenticationInfo, uploadHttpPost, progressionModel, file.toFile(), null);
472
473 }
474 } catch (QuadrigeTechnicalException e) {
475 log.error(I18n.t("quadrige3.error.remote.upload.failed", e.getMessage()), e);
476 throw e;
477 }
478
479 if (multipleFiles) {
480 Files.deleteQuietly(filesToUpload);
481 }
482 }
483
484
485
486
487 @Override
488 public SynchroProgressionVO startExport(AuthenticationInfo authenticationInfo,
489 SynchroExportContextVO exportContextVO,
490 ProgressionCoreModel progressionModel) {
491 Assert.notNull(exportContextVO);
492
493 try {
494 progressionModel.setMessage(t("quadrige3.synchro.progress.start"));
495
496
497 checkVersion(authenticationInfo);
498
499
500 HttpPost request = createHttpPostWithStringEntity(URL_EXPORT_START, exportContextVO);
501
502
503 SynchroProgressionVO result = httpService.executeRequest(authenticationInfo, request, SynchroProgressionVO.class);
504
505 progressionModel.setMessage(result.getMessage());
506 progressionModel.setCurrent(result.getIncrement());
507
508 return result;
509 } catch (QuadrigeTechnicalException e) {
510 log.error(I18n.t("quadrige3.error.remote.startExport.failed", e.getMessage()), e);
511 throw e;
512 }
513 }
514
515
516
517
518 @Override
519 public void stopExport(AuthenticationInfo authenticationInfo, String exportJobId) {
520
521 HttpGet request = new HttpGet(httpService.getPathUri(String.format(URL_EXPORT_STOP, exportJobId)));
522
523
524 httpService.executeRequest(authenticationInfo, request);
525
526 }
527
528
529
530
531 @Override
532 public SynchroResult downloadExportResult(AuthenticationInfo authenticationInfo,
533 SynchroExportContextVO context,
534 ProgressionCoreModel progressionModel) throws Exception {
535
536 File exportDir = configuration.getTempDirectory();
537 FileUtils.forceMkdir(exportDir);
538 String fileName = FilenameUtils.getBaseName(context.getFileName()) + ".json";
539 File downloadedFile = new File(exportDir, fileName);
540
541 progressionModel.setMessage(t("quadrige3.synchro.progress.download"));
542
543
544 HttpGet downloadHttpGet = new HttpGet(httpService.getPathUri(String.format(URL_EXPORT_FILES, fileName)));
545 httpService.executeDownloadFileRequest(authenticationInfo, downloadHttpGet, progressionModel, downloadedFile);
546
547 SynchroResult result = null;
548
549 if (downloadedFile.exists()) {
550 result = Gsons.deserializeFile(downloadedFile, SynchroResult.class);
551 FileUtils.deleteQuietly(downloadedFile);
552
553 if (result == null) {
554 throw new QuadrigeTechnicalException(t("quadrige3.error.synchro.export.resultFile.read", downloadedFile.getAbsolutePath()));
555 }
556 }
557
558 return result;
559 }
560
561 @Override
562 public boolean downloadPhoto(AuthenticationInfo authenticationInfo, int photoRemoteId, String targetFile, ProgressionCoreModel progressionModel) throws Exception {
563
564 File downloadedPhoto = new File(targetFile);
565 Assert.isTrue(downloadedPhoto.isAbsolute(), "targetFile parameter must be an absolute pathname");
566 if (downloadedPhoto.exists()) {
567 log.warn(String.format("the photo %s already exists, it will be overridden", targetFile));
568 }
569
570
571 HttpGet downloadHttpGet = new HttpGet(httpService.getPathUri(String.format(URL_IMPORT_PHOTO, photoRemoteId)));
572 httpService.executeDownloadFileRequest(authenticationInfo, downloadHttpGet, progressionModel, downloadedPhoto);
573
574 return downloadedPhoto.exists();
575 }
576
577
578
579
580 @Override
581 public void acknowledgeExport(AuthenticationInfo authenticationInfo, SynchroExportContextVO context) {
582 try {
583
584
585 checkVersion(authenticationInfo);
586
587
588 HttpPost startHttpPost = createHttpPostWithStringEntity(URL_EXPORT_ACKNOWLEDGE, context);
589
590 httpService.executeRequest(authenticationInfo, startHttpPost);
591
592 } catch (QuadrigeTechnicalException e) {
593 log.error(I18n.t("quadrige3.error.remote.acknowledgeExport.failed", e.getMessage()), e);
594
595 }
596 }
597
598
599
600
601 @Override
602 public List<ProgramVO> savePrograms(AuthenticationInfo authenticationInfo, List<ProgramVO> programs) {
603 return executeRemoteUpdateTyped(
604 URL_PROGRAM_SAVE_LIST,
605 I18n.t("quadrige3.error.remote.programs.save"),
606 authenticationInfo,
607 programs,
608 new TypeToken<ArrayList<ProgramVO>>() {
609 },
610 true);
611 }
612
613
614
615
616 @Override
617 public void clearReferentialUpdateDateCache(AuthenticationInfo authenticationInfo) {
618
619 try {
620
621
622 HttpGet request = new HttpGet(httpService.getPathUri(URL_IMPORT_REFERENTIAL_UPDATE_DATE_CLEAR_CACHE));
623
624
625 httpService.executeRequest(authenticationInfo, request);
626
627 } catch (QuadrigeTechnicalException e) {
628 log.error(I18n.t("quadrige3.error.remote.referential.clearUpdateDateCache.failed", e.getMessage()), e);
629 throw e;
630 }
631
632 }
633
634 @Override
635 public Date getReferentialUpdateDate(AuthenticationInfo authenticationInfo) {
636
637 try {
638
639
640 HttpGet request = new HttpGet(httpService.getPathUri(URL_IMPORT_REFERENTIAL_UPDATE_DATE));
641
642
643 return httpService.executeRequest(authenticationInfo, request, Date.class);
644
645 } catch (QuadrigeTechnicalException e) {
646 log.error(I18n.t("quadrige3.error.remote.referential.updateDate.failed", e.getMessage()), e);
647 throw e;
648 }
649 }
650
651
652
653
654 @Override
655 public List<CampaignVO> saveCampaigns(AuthenticationInfo authenticationInfo, Collection<CampaignVO> campaigns) {
656 return executeRemoteUpdateTyped(
657 URL_CAMPAIGN_SAVE_LIST,
658 I18n.t("quadrige3.error.remote.campaigns.save"),
659 authenticationInfo,
660 campaigns,
661 new TypeToken<ArrayList<CampaignVO>>() {
662 },
663 true);
664 }
665
666 @Override
667 public void deleteCampaigns(AuthenticationInfo authenticationInfo, Collection<Integer> campaignIds) {
668 executeRemoteUpdate(URL_CAMPAIGN_DELETE_LIST,
669 I18n.t("quadrige3.error.remote.campaigns.delete"),
670 authenticationInfo,
671 campaignIds);
672 }
673
674 @Override
675 public List<RuleListVO> saveRuleLists(AuthenticationInfo authenticationInfo, Collection<RuleListVO> ruleLists) {
676 return executeRemoteUpdateTyped(
677 URL_RULE_LIST_SAVE_LIST,
678 I18n.t("quadrige3.error.remote.ruleLists.save"),
679 authenticationInfo,
680 ruleLists,
681 new TypeToken<ArrayList<RuleListVO>>() {
682 },
683 true);
684 }
685
686 @Override
687 public void deleteRuleLists(AuthenticationInfo authenticationInfo, Collection<String> ruleListCds) {
688 executeRemoteUpdate(URL_RULE_LIST_DELETE_LIST,
689 I18n.t("quadrige3.error.remote.ruleLists.delete"),
690 authenticationInfo,
691 ruleListCds);
692 }
693
694 @Override
695 public RuleListVO getRuleListByCode(AuthenticationInfo authenticationInfo, String ruleListCode) {
696 Assert.notNull(ruleListCode);
697
698 if (log.isDebugEnabled()) {
699 log.debug(String.format("Try to retrieve ruleList [%s], from the synchronization server [%s]", ruleListCode, configuration.getSynchronizationSiteUrl()));
700 }
701
702 try {
703
704 HttpGet request = new HttpGet(httpService.getPathUri(String.format(URL_RULE_LIST_GET, ruleListCode)));
705 return httpService.executeRequest(authenticationInfo, request, RuleListVO.class, true);
706
707 } catch (QuadrigeTechnicalException e) {
708 log.error(I18n.t("quadrige3.error.remote.ruleList.get.failed", ruleListCode, e.getMessage()), e);
709 throw e;
710 }
711
712 }
713
714 @Override
715 public GeneralConditionVO getLastNonAcceptedGeneralCondition(AuthenticationInfo authenticationInfo) {
716 if (log.isDebugEnabled()) {
717 log.debug(String.format("Try to retrieve last non-accepted general condition, from the synchronization server [%s]", configuration.getSynchronizationSiteUrl()));
718 }
719
720 HttpGet request = new HttpGet(httpService.getPathUri(URL_GENERAL_CONDITION_GET));
721 return httpService.executeRequest(authenticationInfo, request, GeneralConditionVO.class, true);
722 }
723
724 @Override
725 public void acceptGeneralCondition(AuthenticationInfo authenticationInfo, int id) {
726 if (log.isDebugEnabled()) {
727 log.debug(String.format("Try to accept general condition [%s], from the synchronization server [%s]", id, configuration.getSynchronizationSiteUrl()));
728 }
729
730 HttpPost request = createHttpPostWithStringEntity(URL_GENERAL_CONDITION_ACCEPT, id);
731 httpService.executeRequest(authenticationInfo, request);
732 }
733
734 @Override
735 public SynchroProgressionVO getExportLastStatus(AuthenticationInfo authenticationInfo,
736 String exportJobId,
737 ProgressionCoreModel progressionModel) throws Exception {
738
739 SynchroProgressionVO result = null;
740 int refreshTimeout = configuration.getSynchronizationRefreshTimeout();
741
742 try {
743 HttpGet request = new HttpGet(httpService.getPathUri(String.format(URL_EXPORT_STATUS, exportJobId)));
744
745 progressionModel.setTotal(100);
746
747 SynchroProgressionStatus status = null;
748 while (status == null || isRunningStatus(status)) {
749
750
751 result = httpService.executeRequest(authenticationInfo, request, SynchroProgressionVO.class);
752
753 status = SynchroProgressionStatus.valueOf(result.getStatus());
754
755
756 progressionModel.setMessage(result.getMessage());
757 progressionModel.setCurrent(result.getIncrement());
758
759
760 Thread.sleep(refreshTimeout);
761 }
762
763 return result;
764 } catch (QuadrigeTechnicalException e) {
765 log.error(I18n.t("quadrige3.error.remote.export.status.failed", e.getMessage()), e);
766 throw e;
767 }
768 }
769
770
771
772
773
774
775
776
777
778
779
780 private boolean isRunningStatus(SynchroProgressionStatus status) {
781 return status == SynchroProgressionStatus.RUNNING
782 || status == SynchroProgressionStatus.WAITING_EXECUTION;
783 }
784
785
786
787
788
789
790
791
792
793
794
795
796 private SynchroProgressionVO getImportLastStatus(AuthenticationInfo authenticationInfo,
797 String importJobId,
798 ProgressionCoreModel progressionModel) throws Exception {
799 SynchroProgressionVO result = null;
800 int refreshTimeout = configuration.getSynchronizationRefreshTimeout();
801
802 try {
803 HttpGet request = new HttpGet(httpService.getPathUri(String.format(URL_IMPORT_STATUS, importJobId)));
804
805 progressionModel.setTotal(100);
806
807 SynchroProgressionStatus status = null;
808 String filename = null;
809 while (status == null || isRunningStatus(status)) {
810
811
812 result = httpService.executeRequest(authenticationInfo, request, SynchroProgressionVO.class);
813
814
815 if (filename == null && StringUtils.isNotBlank(result.getFileName())) {
816 filename = result.getFileName();
817 }
818
819 status = SynchroProgressionStatus.valueOf(result.getStatus());
820
821
822 progressionModel.setMessage(result.getMessage());
823 progressionModel.setCurrent(result.getIncrement());
824
825
826 Thread.sleep(refreshTimeout);
827 }
828
829
830 result.setFileName(filename);
831
832 return result;
833 } catch (QuadrigeTechnicalException e) {
834 log.error(I18n.t("quadrige3.error.remote.import.status.failed", e.getMessage()), e);
835 throw e;
836 }
837 }
838
839 private <R> List<R> executeRemoteUpdateTyped(
840 final String postPath,
841 final String errorMessagePrefix,
842 AuthenticationInfo authenticationInfo,
843 Object data,
844 TypeToken<? extends List<R>> typeToken,
845 boolean checkNotEmptyResult) {
846
847 List<R> result = executeRemoteUpdate(
848 postPath,
849 errorMessagePrefix,
850 authenticationInfo,
851 data,
852 typeToken.getType()
853 );
854
855 if (checkNotEmptyResult && CollectionUtils.isEmpty(result)) {
856 log.error(errorMessagePrefix + " " + I18n.t("quadrige3.error.remote.update.emptyResponse"));
857 throw new QuadrigeTechnicalException(errorMessagePrefix + " " + I18n.t("quadrige3.error.remote.update.emptyResponse"));
858 }
859
860 return result;
861
862 }
863
864 private void executeRemoteUpdate(
865 final String postPath,
866 final String logMessagePrefix,
867 AuthenticationInfo authenticationInfo,
868 Object data) {
869
870 executeRemoteUpdate(postPath, logMessagePrefix, authenticationInfo, data, null);
871 }
872
873 private <T> T executeRemoteUpdate(
874 final String postPath,
875 final String errorMessagePrefix,
876 AuthenticationInfo authenticationInfo,
877 Object data,
878 Type resultType
879 ) {
880
881 try {
882
883
884 checkVersion(authenticationInfo);
885
886
887 HttpPost request = createHttpPostWithStringEntity(postPath, data);
888
889
890 return httpService.executeRequest(authenticationInfo, request, resultType);
891
892 } catch (BadUpdateDtException e) {
893 throw new QuadrigeBusinessException(errorMessagePrefix + " " + I18n.t("quadrige3.error.remote.update.badUpdateDate", e.getMessage()), e);
894 } catch (DataLockedException e) {
895 throw new QuadrigeBusinessException(errorMessagePrefix + " " + I18n.t("quadrige3.error.remote.update.dataLocked"), e);
896 } catch (SaveForbiddenException | DeleteForbiddenException e) {
897
898 throw e;
899 } catch (Exception e) {
900 log.error(errorMessagePrefix + " " + I18n.t("quadrige3.error.remote.update.failed", e.getMessage()), e);
901 throw new QuadrigeTechnicalException(errorMessagePrefix + " " + I18n.t("quadrige3.error.remote.update.failed", e.getMessage()), e);
902 }
903 }
904
905 private HttpPost createHttpPostWithStringEntity(
906 final String postPath,
907 Object data) throws DataLockedException {
908
909 HttpPost request = new HttpPost(httpService.getPathUri(postPath));
910 StringEntity entity = new StringEntity(httpService.getGson().toJson(data), ContentType.APPLICATION_JSON);
911 request.setEntity(entity);
912
913 return request;
914
915 }
916 }