View Javadoc
1   package fr.ifremer.quadrige3.ui.swing.synchro.action;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 UI Common
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 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 fr.ifremer.quadrige3.core.dao.technical.Assert;
27  import fr.ifremer.quadrige3.core.dao.technical.Daos;
28  import fr.ifremer.quadrige3.core.exception.QuadrigeTechnicalException;
29  import fr.ifremer.quadrige3.core.security.AuthenticationInfo;
30  import fr.ifremer.quadrige3.core.security.SecurityContextHelper;
31  import fr.ifremer.quadrige3.core.service.ClientServiceLocator;
32  import fr.ifremer.quadrige3.synchro.meta.referential.ReferentialSynchroTables;
33  import fr.ifremer.quadrige3.synchro.service.client.SynchroClientService;
34  import fr.ifremer.quadrige3.synchro.service.client.vo.SynchroClientImportResult;
35  import fr.ifremer.quadrige3.synchro.vo.SynchroImportContextVO;
36  import fr.ifremer.quadrige3.synchro.vo.SynchroProgressionStatus;
37  import fr.ifremer.quadrige3.ui.swing.action.AbstractReloadCurrentScreenAction;
38  import fr.ifremer.quadrige3.ui.swing.content.AbstractMainUIHandler;
39  import fr.ifremer.quadrige3.ui.swing.synchro.SynchroUIContext;
40  import fr.ifremer.quadrige3.ui.swing.synchro.SynchroUIHandler;
41  import fr.ifremer.quadrige3.ui.swing.synchro.resolver.SynchroRejectedRowUIResolver;
42  import org.apache.commons.collections4.CollectionUtils;
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  import org.nuiton.i18n.I18n;
46  import org.nuiton.jaxx.application.ApplicationIOUtil;
47  import org.nuiton.updater.ApplicationUpdater;
48  import org.nuiton.util.FileUtil;
49  
50  import java.io.File;
51  import java.util.List;
52  
53  import static org.nuiton.i18n.I18n.t;
54  
55  /**
56   * <p>ImportSynchroApplyAction class.</p>
57   *
58   * @author Ludovic Pecquot <ludovic.pecquot@e-is.pro>
59   */
60  public class ImportSynchroApplyAction extends AbstractReloadCurrentScreenAction {
61  
62      private static final Log log = LogFactory.getLog(ImportSynchroApplyAction.class);
63  
64      private File dbDirToImport;
65  
66      private boolean silent = false;
67      private boolean needAuthentication = false;
68      private boolean hasReferential = false;
69      private boolean hasData = false;
70  
71      /**
72       * <p>Constructor for ImportSynchroApplyAction.</p>
73       *
74       * @param handler a {@link AbstractMainUIHandler} object.
75       */
76      public ImportSynchroApplyAction(AbstractMainUIHandler handler) {
77          super(handler, true);
78          setActionDescription(t("quadrige3.action.synchro.import.title"));
79      }
80  
81      private SynchroUIContext getSynchroUIContext() {
82          return getContext().getSynchroContext();
83      }
84  
85      private SynchroUIHandler getSynchroHandler() {
86          return getContext().getSynchroHandler();
87      }
88  
89      /**
90       * <p>Setter for the field <code>silent</code>.</p>
91       *
92       * @param silent a boolean.
93       */
94      public void setSilent(boolean silent) {
95          this.silent = silent;
96      }
97  
98      /**
99       * {@inheritDoc}
100      */
101     @Override
102     public boolean prepareAction() throws Exception {
103         super.prepareAction();
104 
105         // get the db directory from context 
106         dbDirToImport = getSynchroUIContext().getWorkingDirectory();
107 
108         // if dbDirToImport is not set, try to get it from file
109         if (dbDirToImport == null) {
110 
111             File userDir = getSynchroUIContext().getImportDirectory();
112             if (userDir.isDirectory()) {
113 
114                 List<File> files = FileUtil.getSubDirectories(userDir);
115                 if (CollectionUtils.isEmpty(files)) {
116                     return false;
117                 }
118                 if (files.size() > 1) {
119                     // should never append but find the newest one
120                     files.sort((f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified()));
121                 }
122                 dbDirToImport = files.get(0);
123             }
124         }
125 
126         if (!dbDirToImport.isDirectory()) {
127             throw new QuadrigeTechnicalException(I18n.t("quadrige3.error.directory.not.exists", dbDirToImport.getAbsolutePath()));
128         }
129 
130         // Normalize the DB directory
131         dbDirToImport = Daos.checkAndNormalizeDbDirectory(dbDirToImport);
132 
133         getSynchroHandler().hidePopup();
134 
135         return true;
136     }
137 
138     /**
139      * {@inheritDoc}
140      */
141     @Override
142     public void doActionBeforeReload() throws Exception {
143         Assert.notNull(dbDirToImport);
144 
145         createProgressionUIModel(103);
146 
147         // get actual version
148         String actualVersion = ApplicationUpdater.loadVersionFile("db", getConfig().getDbDirectory());
149         String newVersion = ApplicationUpdater.loadVersionFile("synchro db", dbDirToImport);
150         if (log.isInfoEnabled()) {
151             log.info(String.format("A database update was downloaded (oldVersion: %s, newVersion: %s), will launch a referential & data synchronize operation ", actualVersion, newVersion));
152         }
153 
154         SynchroClientService service = ClientServiceLocator.instance().getSynchroClientService();
155         SynchroImportContextVO contextVO = getSynchroUIContext().getSynchroImportContext();
156         SynchroClientImportResult result = service.importFromTempDb(
157                 SecurityContextHelper.getQuadrigeUserId(),
158                 dbDirToImport,
159                 contextVO,
160                 new SynchroRejectedRowUIResolver(getContext().getDialogHelper(), true/*isImport*/),
161                 getProgressionUIModel(),
162                 100);
163 
164         // check if updates
165         hasReferential = result.getReferentialResult() != null && result.getReferentialResult().getTotalTreated() > 0;
166         hasData = result.getDataResult() != null && result.getDataResult().getTotalTreated() > 0;
167 
168         // Reset all cache (if referential updates)
169         if (hasReferential) {
170             if (log.isInfoEnabled()) {
171                 log.info("Reset all caches.");
172             }
173             getProgressionUIModel().setMessage(t("quadrige3.synchro.progress.resetCache"));
174             getContext().reloadDbCache(getProgressionUIModel());
175 
176             // Check for user privilege changes
177             if (result.getReferentialResult().getNbUpdates(ReferentialSynchroTables.QUSER_PRIVILEGE.name()) > 0) {
178                 // re-authenticate the current user in case of its privilege have changed (Mantis #38841)
179                 getContext().tryReAuthenticate();
180             }
181         }
182 
183         if (!getContext().isAuthenticated()) {
184             // If the login has changed to another user, the re-authentication could have failed
185             // Do not try to store the import context (mantis #23535) because the user id is not known
186             needAuthentication = true;
187             if (log.isInfoEnabled()) {
188                 log.warn(t("quadrige3.action.synchro.import.success.notAuthenticated"));
189             }
190             // reset synchronization context
191             getSynchroUIContext().resetImportContext();
192             getProgressionUIModel().increments(2);
193         } else {
194             getProgressionUIModel().increments(t("quadrige3.synchro.progress.saveContext"));
195 
196             // reset synchronization context
197             getSynchroUIContext().resetImportContext();
198 
199             // Update last update date for referential (only if update done)
200             if (getSynchroUIContext().isImportReferential()) {
201                 getSynchroUIContext().setImportReferentialUpdateDate(result.getReferentialSynchronizationDate());
202             }
203 
204             // Update last update date for data (only if update done and if there are no rejects left)
205             if (getSynchroUIContext().isImportData()) {
206                 getSynchroUIContext().setImportDataUpdateDate(result.getDataSynchronizationDate());
207             }
208             // save context with data date range
209             getSynchroUIContext().saveImportContext(true, true);
210         }
211 
212         getProgressionUIModel().increments(t("quadrige3.synchro.progress.cleanTemporaryFiles"));
213 
214         // clean local directories and send acknowledge to server
215         clean();
216 
217         // Skip screen reloading if no updates, or if already ask (e.g. by the parent action)
218         setSkipScreenReload(silent || isSkipScreenReload() || (!hasData && !hasReferential));
219     }
220 
221     private void clean() throws Exception {
222 
223         // delete imported database on exit
224         ApplicationIOUtil.forceDeleteOnExit(dbDirToImport, t("quadrige3.error.delete.directory", dbDirToImport.getAbsolutePath()));
225 
226         // send acknowledge
227         ImportSynchroAckAction ackAction
228                 = getContext().getActionFactory().createNonBlockingUIAction(
229                 getSynchroHandler(),
230                 ImportSynchroAckAction.class);
231         ackAction.executeAndWait();
232     }
233 
234     /**
235      * {@inheritDoc}
236      */
237     @Override
238     public void postSuccessAction() {
239         super.postSuccessAction();
240 
241         // Force re-authentication
242         if (!needAuthentication) {
243             AuthenticationInfo authenticationInfo = getContext().getAuthenticationInfo();
244             if (authenticationInfo != null) {
245                 boolean authenticated = SecurityContextHelper.authenticate(authenticationInfo.getLogin(), authenticationInfo.getPassword());
246                 if (!authenticated) {
247                     log.error("Cannot reauthenticate !");
248                 }
249             }
250         }
251 
252 
253         getHandler().reloadDbManagerText();
254 
255         // Show correct message (Mantis #49003)
256         String message = hasData
257                 ? t("quadrige3.action.synchro.import.success.data")
258                 : hasReferential
259                 ? t("quadrige3.action.synchro.import.success.referential")
260                 : t("quadrige3.synchro.report.idle");
261         if (needAuthentication)
262             message += " " + t("quadrige3.action.synchro.import.success.notAuthenticated");
263 
264         getSynchroHandler().report(message, !silent);
265 
266         if (log.isInfoEnabled()) {
267             log.info("Synchronization import success");
268         }
269     }
270 
271     /**
272      * {@inheritDoc}
273      */
274     @Override
275     public void postFailedAction(Throwable error) {
276         if (!silent) {
277             super.postFailedAction(error);
278         }
279 
280         getSynchroHandler().report(t("quadrige3.synchro.report.failed"), !silent);
281         getSynchroUIContext().setStatus(SynchroProgressionStatus.FAILED);
282 
283         log.error("Synchronization import failed");
284     }
285 
286     @Override
287     protected void releaseAction() {
288         super.releaseAction();
289 
290         silent = false;
291         needAuthentication = false;
292         hasReferential = false;
293         hasData = false;
294     }
295 }