View Javadoc
1   package fr.ifremer.quadrige2.ui.swing.common.content.db;
2   
3   /*-
4    * #%L
5    * Quadrige2 Core :: Quadrige2 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  
27  import fr.ifremer.quadrige2.core.service.ClientServiceLocator;
28  import fr.ifremer.quadrige2.core.service.persistence.PersistenceService;
29  import fr.ifremer.quadrige2.ui.swing.common.DialogHelper;
30  import fr.ifremer.quadrige2.ui.swing.common.Screen;
31  import fr.ifremer.quadrige2.ui.swing.common.action.AbstractChangeScreenAction;
32  import fr.ifremer.quadrige2.ui.swing.common.content.AbstractMainUIHandler;
33  import fr.ifremer.quadrige2.ui.swing.common.content.login.AuthenticationAction;
34  import fr.ifremer.quadrige2.ui.swing.common.model.ProgressionModel;
35  import fr.ifremer.quadrige2.ui.swing.common.synchro.action.ImportReferentialSynchroAtOnceAction;
36  import org.apache.commons.logging.Log;
37  import org.apache.commons.logging.LogFactory;
38  import org.nuiton.jaxx.application.ApplicationBusinessException;
39  import org.nuiton.jaxx.application.swing.action.ApplicationUIAction;
40  import org.nuiton.updater.ApplicationInfo;
41  import org.nuiton.util.DateUtil;
42  import org.nuiton.version.Version;
43  
44  import javax.swing.JOptionPane;
45  import java.io.File;
46  import java.util.Date;
47  
48  import static org.nuiton.i18n.I18n.n;
49  import static org.nuiton.i18n.I18n.t;
50  
51  /**
52   * To open existing db.
53   *
54   * @since 1.0
55   */
56  public class OpenDbAction extends AbstractChangeScreenAction {
57  
58      /**
59       * Logger.
60       */
61      private static final Log LOG = LogFactory.getLog(OpenDbAction.class);
62  
63      static {
64          n("quadrige2.dbManager.action.importDb.step.open");
65          n("quadrige2.dbManager.action.openDb.step.open");
66          n("quadrige2.dbManager.action.importDb.couldNotOpen");
67          n("quadrige2.dbManager.action.openDb.couldNotOpen");
68          n("quadrige2.dbManager.action.importDb.step.checkSchemaVersion");
69          n("quadrige2.dbManager.action.openDb.step.checkSchemaVersion");
70          n("quadrige2.dbManager.action.importDb.step.close");
71          n("quadrige2.dbManager.action.openDb.step.close");
72          n("quadrige2.dbManager.action.importDb.step.will.migrateSchema");
73          n("quadrige2.dbManager.action.openDb.step.will.migrateSchema");
74      }
75  
76      protected Version dbVersion;
77  
78      protected Version applicationVersion;
79  
80      protected File file;
81  
82      protected boolean updateSchema;
83  
84      protected boolean closeDb;
85  
86      protected String jdbcUrl;
87  
88      protected ApplicationInfo updateDbVersion;
89  
90      /**
91       * indicate this open action is called by import action
92       */
93      protected boolean isAfterImportDb;
94  
95      /**
96       * <p>Constructor for OpenDbAction.</p>
97       *
98       * @param handler a {@link AbstractMainUIHandler} object.
99       */
100     public OpenDbAction(AbstractMainUIHandler handler) {
101         super(handler, true, Screen.HOME);
102 
103         setActionDescription(t("quadrige2.dbManager.action.openDb.tip"));
104     }
105 
106     /**
107      * <p>setAfterImportDb.</p>
108      *
109      * @param isAfterImportDb a boolean.
110      */
111     public void setAfterImportDb(boolean isAfterImportDb) {
112         this.isAfterImportDb = isAfterImportDb;
113     }
114 
115     /** {@inheritDoc} */
116     @Override
117     public boolean prepareAction() throws Exception {
118 
119         jdbcUrl = null;
120         dbVersion = applicationVersion = null;
121         file = null;
122         closeDb = updateSchema = false;
123         updateDbVersion = null;
124 
125         return super.prepareAction();
126     }
127 
128     /** {@inheritDoc} */
129     @Override
130     public void doAction() throws Exception {
131 
132         jdbcUrl = getConfig().getJdbcUrl();
133 
134         if (LOG.isDebugEnabled()) {
135             LOG.debug("Will open db: " + jdbcUrl);
136         }
137 
138         String actionName = isAfterImportDb ? "importDb" : "openDb";
139 
140         // at the beginning 3 steps (open db + check version + check db context)
141         ProgressionModel progressionModel = new ProgressionModel();
142         setProgressionModel(progressionModel);
143         progressionModel.setTotal(3);
144 
145         // ------------------------------------------------------------------ //
146         // --- open db                                                        //
147         // ------------------------------------------------------------------ //
148         PersistenceService persistenceService;
149 
150         progressionModel.increments(t("quadrige2.dbManager.action." + actionName + ".step.open", jdbcUrl));
151         try {
152             getContext().setDbExist(true);
153             getContext().openPersistenceService(isAfterImportDb);
154             persistenceService = ClientServiceLocator.instance().getPersistenceService();
155 
156         } catch (Exception e) {
157 
158             if (LOG.isErrorEnabled()) {
159                 LOG.error("Could not open db", e);
160             }
161             // no more db
162             getContext().closePersistenceService();
163 
164             // could not load db
165             throw new ApplicationBusinessException(t("quadrige2.dbManager.action." + actionName + ".couldNotOpen"), e);
166         }
167 
168 
169         // ------------------------------------------------------------------ //
170         // --- check schema version                                           //
171         // ------------------------------------------------------------------ //
172         progressionModel.increments(t("quadrige2.dbManager.action." + actionName + ".step.checkSchemaVersion"));
173 
174         dbVersion = persistenceService.getDbVersion();
175         if (LOG.isDebugEnabled()) {
176             LOG.debug("Detected database version: " + (dbVersion == null ? "no version" : dbVersion));
177         }
178         applicationVersion = persistenceService.getApplicationVersion();
179 
180         if (LOG.isDebugEnabled()) {
181             LOG.debug("Detected schema version need for application: " + (applicationVersion == null ? "no version" : applicationVersion));
182         }
183 
184         if (dbVersion == null) {
185 
186             // no database version filled (can not migrate schema)
187             displayWarningMessage(t("quadrige2.dbManager.title.schema.toUpdate"), t("quadrige2.dbManager.action.upgradeDb.schema.version.not.found"));
188             closeDb = true;
189 
190         } else if (dbVersion.equals(applicationVersion)) {
191 
192             // database schema is up to date
193             if (LOG.isInfoEnabled()) {
194                 LOG.info("Database schema is up-to-date at version: " + dbVersion);
195             }
196         } else if (dbVersion.compareTo(applicationVersion) < 0) {
197 
198             // database schema need to migrate
199             // ask user to migrate or not (if not will close db)
200             // ask user where to backup db
201             int i = getContext().getDialogHelper().showConfirmDialog(
202                     t("quadrige2.dbManager.action.upgradeDb.schema.to.update.message", dbVersion, applicationVersion),
203                     t("quadrige2.dbManager.title.schema.toUpdate"),
204                     DialogHelper.UPDATE_DB_CANCEL_OPTION);
205             boolean continueAction = i == JOptionPane.OK_OPTION;
206 
207             if (continueAction) {
208                 if (isAfterImportDb || getContext().isDbJustInstalled()) {
209 
210                     // will migrate from import
211                     updateSchema = true;
212                 } else {
213 
214                     String date = DateUtil.formatDate(new Date(), "yyy-MM-dd");
215 
216                     // ask user file where to backup db
217                     file = saveFile(
218                             getConfig().getDbBackupDirectory(),
219                             String.format("%s-db-%s", getConfig().getApplicationName(), date),
220                             "zip",
221                             t("quadrige2.dbManager.title.choose.dbBackupFile"),
222                             t("quadrige2.dbManager.action.chooseDbBackupFile"),
223                             "^.*\\.zip", t("quadrige2.common.file.zip")
224                     );
225 
226                     if (file == null) {
227 
228                         // won't migrate db
229                         closeDb = true;
230 
231                         displayWarningMessage(
232                                 t("quadrige2.dbManager.title.choose.dbBackupFile"),
233                                 t("quadrige2.dbManager.action.upgradeDb.no.backup.db.choosen"));
234                     } else {
235 
236                         updateSchema = true;
237                     }
238                 }
239             } else {
240 
241                 //close db
242                 closeDb = true;
243             }
244         } else {
245 
246             // database schema version is higher than application one
247             if (isAfterImportDb) {
248 
249                 int i = getContext().getDialogHelper().showConfirmDialog(
250                         t("quadrige2.dbManager.action.upgradeDb.schema.too.high", dbVersion, applicationVersion),
251                         t("quadrige2.dbManager.title.schema.toUpdate"),
252                         DialogHelper.LOAD_DB_CANCEL_OPTION);
253                 boolean continueAction = i == JOptionPane.OK_OPTION;
254 
255                 if (!continueAction) {
256                     //close db
257                     closeDb = true;
258                 }
259             } else {
260                 displayWarningMessage(
261                         t("quadrige2.dbManager.title.schema.toUpdate"),
262                         t("quadrige2.dbManager.action.upgradeDb.schema.not.update.message", dbVersion, applicationVersion)
263                 );
264             }
265         }
266         if (closeDb) {
267 
268             // ------------------------------------------------------------------ //
269             // --- close current db                                               //
270             // ------------------------------------------------------------------ //
271             progressionModel.increments(t("quadrige2.dbManager.action." + actionName + ".step.close"));
272             getActionEngine().runInternalAction(getHandler(), CloseDbAction.class);
273 
274             if (!isAfterImportDb) {
275                 setScreen(Screen.MANAGE_DB);
276                 super.doAction();
277             }
278             return;
279         }
280 
281         if (updateSchema) {
282 
283             // need to export db + migrate schema)
284             progressionModel.adaptTotal(progressionModel.getTotal() + ExportDbAction.TOTAL_STEP + 1);
285 
286             if (!isAfterImportDb && file != null) {
287                 // ------------------------------------------------------------------ //
288                 // --- backup current db                                              //
289                 // ------------------------------------------------------------------ //
290                 ApplicationUIAction<ExportDbAction> backupAction
291                         = getActionFactory().createUIAction(getHandler(), ExportDbAction.class);
292                 backupAction.getLogicAction().setProgressionModel(getProgressionModel());
293                 backupAction.getLogicAction().setFile(file);
294                 getActionEngine().runInternalAction(backupAction.getLogicAction());
295             }
296 
297             // ------------------------------------------------------------------ //
298             // --- update schema                                                  //
299             // ------------------------------------------------------------------ //
300             String message = t("quadrige2.dbManager.action." + actionName + ".step.will.migrateSchema", dbVersion, applicationVersion);
301             progressionModel.increments(message);
302             sendMessage(message);
303 
304             ClientServiceLocator.instance().getPersistenceService().updateSchema();
305 
306             sendMessage(t("quadrige2.flash.info.db.schema.updated", dbVersion, applicationVersion));
307         }
308 
309         // ------------------------------------------------------------------ //
310         // --- Authentication                                                 //
311         // ------------------------------------------------------------------ //
312         if (getContext().isPersistenceLoaded() && !getContext().isAuthenticated()) {
313 
314             progressionModel.increments(t("quadrige2.dbManager.action.openDb.step.authenticate"));
315 
316             AuthenticationAction action = new AuthenticationAction(getHandler());
317             getActionEngine().runInternalAction(action);
318 
319         }
320 
321         // ----------------------------------------------------------------------------- //
322         // --- Perform referential updates before checkDbContext (see mantis #30764) --- //
323         // ----------------------------------------------------------------------------- //
324         if (getContext().isSynchroEnabled() && getContext().isDbJustInstalled()) {
325             ImportReferentialSynchroAtOnceAction importAction = getContext().getActionFactory().createLogicAction(getHandler(), ImportReferentialSynchroAtOnceAction.class);
326             getContext().getActionEngine().runInternalAction(importAction);
327         }
328 
329         // ------------------------------------------------------------------ //
330         // --- check db context                                               //
331         // ------------------------------------------------------------------ //
332         progressionModel.increments(t("quadrige2.dbManager.action.openDb.step.check.dbContext", dbVersion, applicationVersion));
333 
334         if (LOG.isDebugEnabled()) {
335             LOG.debug("Check db context");
336         }
337 
338         getContext().setDbJustImportedFromFile(isAfterImportDb);
339 
340         // Prepare the persistence layer
341         getContext().checkDbContext(progressionModel);
342 
343         // ------------------------------------------------------------------ //
344         // --- Check referential updates                                      //
345         // ------------------------------------------------------------------ //
346 //        if (getContext().isSynchroEnabled()) {
347 //            ImportReferentialSynchroAction importSynchroAction = getActionFactory().createLogicAction(handler, ImportReferentialSynchroAction.class);
348 //            importSynchroAction.setSilent(true);
349 //            getActionEngine().runFullInternalAction(importSynchroAction);
350 //        }
351 
352         super.doAction();
353     }
354 
355     /** {@inheritDoc} */
356     @Override
357     public void postSuccessAction() {
358 
359         getHandler().reloadDbManagerText();
360 
361         // make sure title is reloaded
362         getHandler().changeTitle();
363 
364         if (!isAfterImportDb) {
365             if (closeDb) {
366                 sendMessage(t("quadrige2.flash.info.db.not.opened", jdbcUrl));
367             } else {
368                 sendMessage(t("quadrige2.flash.info.db.opened", jdbcUrl));
369             }
370         }
371     }
372 
373     /** {@inheritDoc} */
374     @Override
375     public void postFailedAction(Throwable error) {
376 
377         getHandler().reloadDbManagerText();
378 
379         super.postFailedAction(error);
380     }
381 }