View Javadoc
1   package fr.ifremer.tutti.ui.swing.update.module;
2   
3   /*
4    * #%L
5    * Tutti :: UI
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2012 - 2015 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU General Public License as
13   * published by the Free Software Foundation, either version 3 of the
14   * License, or (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 General Public
22   * License along with this program.  If not, see
23   * <http://www.gnu.org/licenses/gpl-3.0.html>.
24   * #L%
25   */
26  
27  import com.google.common.base.Preconditions;
28  import fr.ifremer.adagio.core.service.technical.synchro.ReferentialSynchroContext;
29  import fr.ifremer.adagio.core.service.technical.synchro.ReferentialSynchroResult;
30  import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModel;
31  import fr.ifremer.tutti.service.PersistenceService;
32  import fr.ifremer.tutti.service.referential.TuttiReferentialSynchronizeService;
33  import fr.ifremer.tutti.ui.swing.TuttiUIContext;
34  import fr.ifremer.tutti.ui.swing.updater.DeleteHelper;
35  import fr.ifremer.tutti.ui.swing.updater.UpdateModule;
36  import org.apache.commons.io.FileUtils;
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.nuiton.jaxx.application.ApplicationIOUtil;
40  import org.nuiton.jaxx.application.ApplicationTechnicalException;
41  import org.nuiton.jaxx.application.swing.action.ApplicationActionUI;
42  import org.nuiton.jaxx.application.type.ApplicationProgressionModel;
43  import org.nuiton.updater.ApplicationInfo;
44  import org.nuiton.updater.ApplicationUpdater;
45  
46  import java.io.File;
47  import java.io.IOException;
48  
49  import static org.nuiton.i18n.I18n.t;
50  
51  /**
52   * Created on 1/28/15.
53   *
54   * @author Tony Chemit - chemit@codelutin.com
55   * @since 3.13
56   */
57  public class DbModuleUpdater extends ModuleUpdaterSupport {
58  
59      /** Logger. */
60      private static final Log log = LogFactory.getLog(DbModuleUpdater.class);
61  
62      protected boolean dbInstalled;
63  
64      protected boolean dbUpdated;
65  
66      public DbModuleUpdater() {
67          super(UpdateModule.db);
68      }
69  
70      public boolean isDbInstalled() {
71          return dbInstalled;
72      }
73  
74      public boolean isDbUpdated() {
75          return dbUpdated;
76      }
77  
78      @Override
79      protected void onUpdateToDo(TuttiUIContext context, ApplicationInfo info) {
80  
81          if (info == null) {
82              dbInstalled = false;
83              dbUpdated = false;
84          } else {
85  
86              if (log.isInfoEnabled()) {
87                  log.info("Find a updatable module : " + updateModule);
88              }
89  
90              if (context.isDbExist()) {
91  
92                  // when db exists always an update
93                  dbUpdated = true;
94              } else {
95  
96                  // when no db, then always install
97                  dbInstalled = true;
98              }
99          }
100 
101     }
102 
103     @Override
104     public void onUpdateDone(TuttiUIContext context, ApplicationInfo info) {
105 
106         if (log.isInfoEnabled()) {
107             log.info(String.format(
108                     "A db update was downloaded (oldVersion: %s, newVersion: %s).",
109                     info.oldVersion, info.newVersion));
110         }
111 
112         if (dbInstalled || dbUpdated) {
113 
114             File source = getDbDirectory(info);
115 
116             if (dbInstalled) {
117 
118                 // first database, just copy it to correct directory
119                 prepareFirstDatabase(context, info, source);
120 
121             } else if (dbUpdated) {
122 
123                 // launch a referential synchronize operation
124                 synchronizeDatabase(context, info, source);
125 
126             }
127 
128             if (log.isInfoEnabled()) {
129                 log.info("Delete update directory: " + source);
130             }
131             try {
132                 FileUtils.deleteDirectory(source);
133             } catch (IOException e) {
134                 throw new ApplicationTechnicalException(t("tutti.applicationUpdater.prepareFirstDB.deleteDirectory.error", source), e);
135             }
136 
137         }
138 
139     }
140 
141     @Override
142     public String getLabel() {
143         return t("tutti.update.db");
144     }
145 
146     protected void prepareFirstDatabase(TuttiUIContext context, ApplicationInfo info, File source) {
147 
148         if (log.isInfoEnabled()) {
149             log.info("First time database was downloaded at version: " + info.newVersion);
150         }
151 
152         File target = context.getConfig().getDbDirectory();
153         if (log.isInfoEnabled()) {
154             log.info("Copy from " + source + " to " + target);
155         }
156 
157         try {
158             FileUtils.copyDirectory(source, target);
159         } catch (IOException e) {
160             throw new ApplicationTechnicalException(t("tutti.applicationUpdater.prepareFirstDB.copyDirectory.error", source, target), e);
161         }
162 
163     }
164 
165     protected void synchronizeDatabase(TuttiUIContext context, ApplicationInfo info, File source) {
166 
167         if (log.isInfoEnabled()) {
168             log.info(String.format("A database update was downloaded (oldVersion: %s, newVersion: %s), will launch a referential synchronize operation ", info.oldVersion, info.newVersion));
169         }
170 
171         TuttiReferentialSynchronizeService service = context.getTuttiReferentialSynchronizeService();
172 
173         File dbDirectory = getDbDirectoryCopy(source);
174 
175         ReferentialSynchroContext synchroContext = service.createSynchroContext(dbDirectory);
176         ReferentialSynchroResult result = synchroContext.getResult();
177 
178         ApplicationActionUI actionUI = context.getActionUI();
179         actionUI.getModel().setProgressionModel(new DelegateProgressionModel(result.getProgressionModel()));
180         service.prepare(synchroContext);
181 
182         if (!result.isSuccess()) {
183             throw new ApplicationTechnicalException(t("tutti.applicationUpdater.synchroDB.prepare.error"), result.getError());
184         }
185 
186         service.synchronize(synchroContext);
187 
188         if (!result.isSuccess()) {
189             throw new ApplicationTechnicalException(t("tutti.applicationUpdater.synchroDB.synchro.error"), result.getError());
190         }
191 
192         // reset cache
193         if (log.isInfoEnabled()) {
194             log.info("Reset all caches.");
195         }
196         PersistenceService persistence = context.getPersistenceService();
197         persistence.clearAllCaches();
198 
199         // clean data context
200         SampleCategoryModel sampleCategoryModel = context.getConfig().getSampleCategoryModel();
201         if (log.isInfoEnabled()) {
202             log.info("SampleCategoryModel to reload: " + sampleCategoryModel);
203         }
204         if (log.isInfoEnabled()) {
205             log.info("Clean data context.");
206         }
207         context.getDataContext().clearContext();
208         if (log.isInfoEnabled()) {
209             log.info("SampleCategoryModel to reload (after clearContext): " + sampleCategoryModel);
210         }
211         context.getDataContext().setSampleCategoryModel(sampleCategoryModel);
212 
213         // replace the version.appup file content
214         File target = context.getConfig().getDbDirectory();
215         File versionFile = ApplicationUpdater.getVersionFile(target);
216         if (log.isInfoEnabled()) {
217             log.info("Replace content of file " + versionFile + " with " + info.newVersion);
218         }
219         try {
220             ApplicationUpdater.storeVersionFile(target, info.newVersion);
221         } catch (IOException e) {
222             throw new ApplicationTechnicalException(
223                     t("tutti.applicationUpdater.synchroDB.writeVersion.error", versionFile));
224         }
225     }
226 
227     protected File getDbDirectory(ApplicationInfo info) {
228         File[] sources = info.destDir.listFiles();
229         Preconditions.checkNotNull(sources, "Downloaded db must have at least on directory, see " + info.destDir);
230         Preconditions.checkState(sources.length == 1, "Downloaded db should contains one directory at " + info.destDir);
231         return sources[0];
232     }
233 
234     protected File getDbDirectoryCopy(File source) {
235 
236         File temporaryDirectory = ApplicationIOUtil.createTemporaryDirectory(this.toString());
237         File[] files = source.listFiles();
238         if (files != null) {
239 
240             for (File file : files) {
241                 ApplicationIOUtil.copyFileToDirectory(file, temporaryDirectory, "Can't copy file " + file + " to directory " + temporaryDirectory);
242             }
243 
244         }
245 
246         try {
247             DeleteHelper.deleteDirectoryOnExit(temporaryDirectory.toPath());
248         } catch (IOException e) {
249             throw new ApplicationTechnicalException("Can't mark directory " + temporaryDirectory + "to be deleted on exit", e);
250         }
251 
252         return temporaryDirectory;
253 
254     }
255 
256     private static class DelegateProgressionModel extends ApplicationProgressionModel {
257 
258         private static final long serialVersionUID = 1L;
259 
260         private final fr.ifremer.adagio.core.type.ProgressionModel progressionModel;
261 
262         public DelegateProgressionModel(fr.ifremer.adagio.core.type.ProgressionModel progressionModel) {
263 
264             this.progressionModel = progressionModel;
265             this.progressionModel.addPropertyChangeListener(evt -> firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()));
266         }
267 
268         @Override
269         public void setMessage(String message) {
270             progressionModel.setMessage(message);
271         }
272 
273         @Override
274         public void increments(String message) {
275             progressionModel.increments(message);
276         }
277 
278         @Override
279         public String getMessage() {
280             return progressionModel.getMessage();
281         }
282 
283         @Override
284         public void setRate(float rate) {
285             progressionModel.setRate(rate);
286         }
287 
288         @Override
289         public float getRate() {
290             return progressionModel.getRate();
291         }
292 
293         @Override
294         public void increments(int nb) {
295             progressionModel.increments(nb);
296         }
297 
298         @Override
299         public void setCurrent(int current) {
300             progressionModel.setCurrent(current);
301         }
302 
303         @Override
304         public int getCurrent() {
305             return progressionModel.getCurrent();
306         }
307 
308         @Override
309         public void adaptTotal(int total) {
310             progressionModel.adaptTotal(total);
311         }
312 
313         @Override
314         public void setTotal(int total) {
315             progressionModel.setTotal(total);
316         }
317 
318         @Override
319         public int getTotal() {
320             return progressionModel.getTotal();
321         }
322     }
323 }