View Javadoc
1   package fr.ifremer.dali.ui.swing.action;
2   
3   /*
4    * #%L
5    * Dali :: UI
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2014 - 2015 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import com.google.common.base.Predicate;
27  import com.google.common.collect.Multimap;
28  import fr.ifremer.dali.dto.DaliBeans;
29  import fr.ifremer.dali.dto.system.synchronization.SynchroChangesDTO;
30  import fr.ifremer.dali.dto.system.synchronization.SynchroRowDTO;
31  import fr.ifremer.dali.dto.system.synchronization.SynchroTableDTO;
32  import fr.ifremer.dali.service.DaliServiceLocator;
33  import fr.ifremer.dali.service.synchro.SynchroClientService;
34  import fr.ifremer.dali.ui.swing.DaliUIContext;
35  import fr.ifremer.dali.ui.swing.content.DaliMainUIHandler;
36  import fr.ifremer.dali.ui.swing.content.synchro.changes.duplicate.SynchroDuplicatesUI;
37  import fr.ifremer.quadrige3.core.security.SecurityContextHelper;
38  import fr.ifremer.quadrige3.synchro.meta.data.DataSynchroTables;
39  import fr.ifremer.quadrige3.synchro.service.client.SynchroRejectedRowResolver;
40  import fr.ifremer.quadrige3.synchro.service.client.vo.SynchroClientImportFromFileResult;
41  import fr.ifremer.quadrige3.synchro.service.client.vo.SynchroOperationType;
42  import fr.ifremer.quadrige3.synchro.vo.SynchroProgressionStatus;
43  import fr.ifremer.quadrige3.ui.swing.action.AbstractReloadCurrentScreenAction;
44  import fr.ifremer.quadrige3.ui.swing.model.ProgressionUIModel;
45  import fr.ifremer.quadrige3.ui.swing.synchro.SynchroDirection;
46  import fr.ifremer.quadrige3.ui.swing.synchro.SynchroUIContext;
47  import fr.ifremer.quadrige3.ui.swing.synchro.SynchroUIHandler;
48  import fr.ifremer.quadrige3.ui.swing.synchro.action.AbstractSynchroAction;
49  import fr.ifremer.quadrige3.ui.swing.synchro.action.ImportSynchroStartAction;
50  import fr.ifremer.quadrige3.ui.swing.synchro.resolver.SynchroRejectedRowUIResolver;
51  import org.apache.commons.logging.Log;
52  import org.apache.commons.logging.LogFactory;
53  
54  import java.awt.Dimension;
55  import java.io.File;
56  
57  import static org.nuiton.i18n.I18n.t;
58  
59  /**
60   * <p>ImportFromFileSynchroAction class.</p>
61   *
62   * @author benoit.lavenier@e-is.pro
63   * @since 1.0
64   */
65  public class ImportFromFileSynchroAction extends AbstractReloadCurrentScreenAction {
66      private static final Log log = LogFactory.getLog(ImportFromFileSynchroAction.class);
67  
68      private AbstractSynchroAction nextSynchroAction;
69      private File file = null;
70  
71      /**
72       * <p>Constructor for ImportFromFileSynchroAction.</p>
73       *
74       * @param handler a {@link DaliMainUIHandler} object.
75       */
76      public ImportFromFileSynchroAction(DaliMainUIHandler handler) {
77          super(handler, true);
78          setActionDescription(t("dali.action.synchro.importFromFile.title"));
79      }
80  
81      @Override
82      public DaliUIContext getContext() {
83          return (DaliUIContext) super.getContext();
84      }
85  
86      private SynchroUIContext getSynchroUIContext() {
87          return getContext().getSynchroContext();
88      }
89  
90      private SynchroUIHandler getSynchroHandler() {
91          return getContext().getSynchroHandler();
92      }
93  
94      /** {@inheritDoc} */
95      @Override
96      public boolean prepareAction() throws Exception {
97  
98          boolean doAction = super.prepareAction();
99  
100         if (doAction) {
101 
102             if (file == null) {
103 
104                 // choose file to import
105                 file = chooseFile(
106                         t("dali.action.synchro.importFromFile.choose.title"),
107                         t("dali.action.synchro.importFromFile.choose.buttonLabel"),
108                         "^.*\\.zip", t("dali.common.file.zip")
109                 );
110 
111                 if (file == null) {
112 
113                     displayWarningMessage(
114                             t("dali.action.synchro.importFromFile.choose.title"),
115                             t("dali.action.synchro.importFromFile.choose.noFile")
116                     );
117 
118                     doAction = false;
119                 }
120             }
121         }
122         return doAction;
123     }
124 
125     /** {@inheritDoc} */
126     @Override
127     public void doActionBeforeReload() {
128         // test actual progression
129         getSynchroUIContext().getProgressionModel().clear();
130         getSynchroUIContext().setDirection(SynchroDirection.IMPORT);
131         getSynchroUIContext().loadImportContext();
132         boolean isSynchronizationUsingServer = getConfig().isSynchronizationUsingServer();
133 
134         // If last synchronization has failedAction
135         if (getSynchroUIContext().getStatus() == SynchroProgressionStatus.FAILED) {
136             getSynchroHandler().report(t("quadrige3.synchro.report.failed"));
137             return;
138         }
139 
140         // If synchronisation file is already here, apply it
141         if (isSynchronizationUsingServer && getSynchroUIContext().getStatus() == SynchroProgressionStatus.SUCCESS && getSynchroUIContext().getWorkingDirectory() != null) {
142             // already downloaded
143             getSynchroHandler().showValidApplyPopup();
144             return;
145         }
146 
147         // If last status was RUNNING
148         // AND there is a jobId (mantis #24916)
149         if (isSynchronizationUsingServer
150                 && getSynchroUIContext().isRunningStatus()) {
151             if (getSynchroUIContext().getImportJobId() != null) {
152                 nextSynchroAction = getContext().getActionFactory().createNonBlockingUIAction(getSynchroHandler(), ImportSynchroStartAction.class);
153                 return;
154             } else {
155                 // This should never append, but reset some attributes anyway (NOT a complete reset, to avoid Direction reset...)
156                 getSynchroUIContext().setImportJobId(null);
157                 getSynchroUIContext().setStatus(SynchroProgressionStatus.NOT_STARTED);
158             }
159         }
160 
161         // select data updates only
162         getSynchroUIContext().setImportReferential(false);
163         getSynchroUIContext().setImportData(true);
164         getSynchroUIContext().setStatus(SynchroProgressionStatus.RUNNING);
165         getSynchroUIContext().saveImportContext();
166 
167         SynchroClientService synchroService = DaliServiceLocator.instance().getSynchroClientService();
168         int userId = SecurityContextHelper.getQuadrigeUserId();
169 
170         // First, get import changes
171         ProgressionUIModel progressionModel = createProgressionUIModel(100);
172         SynchroChangesDTO changes = synchroService.getImportFileChangesAsDTO(
173                 userId,
174                 file,
175                 getSynchroUIContext().getSynchroImportContext(),
176                 progressionModel,
177                 100
178         );
179         progressionModel.setTotal(100);
180 
181         // If no changes detected: exit
182         if (changes.isTablesEmpty()) {
183             getSynchroUIContext().resetImportContext();
184             getSynchroHandler().report(t("dali.error.synchro.importFromFile.noData"), true);
185             setSkipScreenReload(true);
186             return;
187         }
188 
189         // Filter changes
190         SynchroChangesDTO referentialChangesToApply = synchroService.getReferentialSynchroChangesToApplyFromFile(changes);
191 
192             /* LP 16/11/2015 : SynchroChangesUI is disabled for the moment
193             SynchroChangesUI diffUI = new SynchroChangesUI(getUI());
194             diffUI.getModel().setChanges(changes);
195             handler.openDialog(diffUI, t("dali.action.synchro.importFromFile.changes.title"), new Dimension(800, 400));
196 
197             // no change to apply (or user cancelled) : exit
198             if (!diffUI.getModel().isChangesValidated()) {
199 
200                 getSynchroUIContext().resetImportContext();
201                 setSkipScreenReload(true);
202                 return;
203             }
204             */
205 
206         // get survey DUPLICATION or INSERT
207         SynchroChangesDTO surveyChangesToApply = synchroService.getSurveySynchroChangesFromFile(changes);
208 
209         // Select Survey duplicate to import as insert
210         if (surveyChangesToApply != null && !surveyChangesToApply.isTablesEmpty()) {
211 
212             SynchroDuplicatesUI duplicatesUI = new SynchroDuplicatesUI(getContext());
213             duplicatesUI.getModel().setTableNameFilter(DataSynchroTables.SURVEY.name());
214             duplicatesUI.getModel().setChanges(surveyChangesToApply);
215             getHandler().openDialogForceOnTop(duplicatesUI, new Dimension(800, 400));
216             if (duplicatesUI.getModel().isChangesValidated()) {
217                 surveyChangesToApply = duplicatesUI.getModel().getChanges();
218             } else {
219                 surveyChangesToApply = null;
220             }
221 
222         }
223 
224         // abort here if nothing to import
225         if (referentialChangesToApply.isTablesEmpty() && isSurveyChangesEmpty(surveyChangesToApply)) {
226             getSynchroUIContext().resetImportContext();
227             getSynchroHandler().report(t("dali.error.synchro.importFromFile.noData"), true);
228             setSkipScreenReload(true);
229             return;
230         }
231 
232         // Build referential PK includes Map
233         Multimap<String, String> referentialPkIncludes = synchroService.toPkToIncludesMap(referentialChangesToApply);
234         getSynchroUIContext().setImportReferentialPkIncludes(referentialPkIncludes);
235 
236         // build surveys PK include Map if surveyChangesToApply if not null
237         if (isSurveyChangesEmpty(surveyChangesToApply)) {
238             // disable import data if user cancel survey import (see Mantis#0029876)
239             getSynchroUIContext().setImportData(false);
240         } else {
241             Multimap<String, String> surveyPkIncludes = synchroService.toPkToIncludesMap(surveyChangesToApply);
242             getSynchroUIContext().setImportDataPkIncludes(surveyPkIncludes);
243             // enable force duplication in context only if replace (see Mantis #34569)
244             if (hasSurveyReplace(surveyChangesToApply)) {
245                 getSynchroUIContext().setForceDuplication(true);
246             }
247         }
248 
249         // build temp database and export local to temp
250         progressionModel.setTotal(100);
251         progressionModel.setMessage(t("quadrige3.synchro.progress.import"));
252         SynchroRejectedRowResolver rejectResolver = new SynchroRejectedRowUIResolver(getContext().getDialogHelper(), true /*isImport*/);
253 
254         // export directory is set by the synchronization service
255         SynchroClientImportFromFileResult importResult = synchroService.importFromFile(
256                 userId,
257                 file,
258                 getSynchroUIContext().getSynchroImportContext(),
259                 rejectResolver,
260                 progressionModel,
261                 100);
262 
263         boolean isReferentialUpdated = importResult.getReferentialResult() != null && importResult.getReferentialResult().getTotalTreated() > 0;
264         boolean isDataUpdated = importResult.getDataResult() != null && importResult.getDataResult().getTotalTreated() > 0;
265 
266         // reset cache
267         if (isReferentialUpdated) {
268             if (log.isInfoEnabled()) {
269                 log.info("Reset all caches.");
270             }
271             progressionModel.setMessage(t("quadrige3.synchro.progress.resetCache"));
272             getContext().reloadDbCache(progressionModel);
273         }
274 
275         if (!getContext().isAuthenticated()) {
276             // If the login has changed to another user, the re-authentication could have failed
277             // Do not try to store the import context (mantis #23535) because the user id is not known
278             if (log.isInfoEnabled()) {
279                 log.warn(t("dali.action.synchro.import.success.notAuthenticated"));
280             }
281             // reset synchronization context
282             getSynchroUIContext().resetImportContext();
283             getSynchroHandler().report(t("dali.action.synchro.import.success.notAuthenticated"), true);
284             progressionModel.increments(2);
285         } else {
286             getSynchroHandler().report(t("dali.action.synchro.import.success"), true);
287         }
288 
289         // delegate progression model from SynchroUIContext
290         progressionModel.setTotal(100);
291 
292         // Skip screen reloading if NO updates
293         setSkipScreenReload(!isDataUpdated && !isReferentialUpdated);
294     }
295 
296     private boolean hasSurveyReplace(SynchroChangesDTO surveyChangesToApply) {
297 
298         SynchroTableDTO surveyTable = null;
299         for (SynchroTableDTO table : surveyChangesToApply.getTables()) {
300             if (table.getName().equalsIgnoreCase(DataSynchroTables.SURVEY.name())) {
301                 surveyTable = table;
302                 break;
303             }
304         }
305 
306         return surveyTable != null && !DaliBeans.filterCollection(surveyTable.getRows(),
307                 (Predicate<SynchroRowDTO>) input -> input != null && SynchroOperationType.DUPLICATE.toString().equalsIgnoreCase(input.getOperationType()))
308                 .isEmpty();
309     }
310 
311     private boolean isSurveyChangesEmpty(SynchroChangesDTO surveyChanges) {
312         if (surveyChanges == null || surveyChanges.isTablesEmpty()) {
313             return true;
314         }
315         for (SynchroTableDTO table : surveyChanges.getTables()) {
316             if (DataSynchroTables.SURVEY.name().equalsIgnoreCase(table.getName())) {
317                 return table.isRowsEmpty();
318             }
319         }
320         return true;
321     }
322 
323     /** {@inheritDoc} */
324     @Override
325     public void postSuccessAction() {
326         super.postSuccessAction();
327 
328         getSynchroUIContext().saveImportContext();
329 
330         if (nextSynchroAction != null && getConfig().isSynchronizationUsingServer()) {
331             nextSynchroAction.execute();
332         }
333 
334     }
335 
336     /** {@inheritDoc} */
337     @Override
338     public void postFailedAction(Throwable error) {
339         super.postFailedAction(error);
340 
341         getSynchroHandler().report(t("quadrige3.synchro.report.failed"), true);
342         getSynchroUIContext().setStatus(SynchroProgressionStatus.FAILED);
343 
344         log.error("Synchronization import from file failed");
345     }
346 
347     /** {@inheritDoc} */
348     @Override
349     protected void releaseAction() {
350         super.releaseAction();
351         file = null;
352         nextSynchroAction = null;
353     }
354 
355 }