View Javadoc
1   package fr.ifremer.quadrige2.ui.swing.common.callback;
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 com.google.common.base.Charsets;
28  import com.google.common.collect.Lists;
29  import com.google.common.collect.Maps;
30  import com.google.common.io.Files;
31  import fr.ifremer.quadrige2.ui.swing.common.ApplicationUIContext;
32  import fr.ifremer.quadrige2.ui.swing.common.action.AbstractAction;
33  import fr.ifremer.quadrige2.ui.swing.common.model.ProgressionModel;
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  import org.nuiton.jaxx.application.ApplicationTechnicalException;
37  import org.nuiton.jaxx.application.swing.action.ApplicationActionException;
38  import org.nuiton.updater.ApplicationInfo;
39  import org.nuiton.updater.ApplicationUpdater;
40  import org.nuiton.updater.ApplicationUpdaterCallback;
41  
42  import java.io.File;
43  import java.io.IOException;
44  import java.util.List;
45  import java.util.Map;
46  import java.util.Properties;
47  
48  import static org.nuiton.i18n.I18n.n;
49  import static org.nuiton.i18n.I18n.t;
50  
51  /**
52   * CallBack to update i18n, help and config.
53   *
54   * @author Ludovic Pecquot
55   * @since 1.2.2
56   */
57  public class DataUpdaterCallBack implements ApplicationUpdaterCallback {
58  
59      /**
60       * Logger.
61       */
62      private static final Log LOG = LogFactory.getLog(DataUpdaterCallBack.class);
63  
64      public enum UpdateType {
65  
66          I18N(n("quadrige2.update.i18n")),
67          HELP(n("quadrige2.update.help")),
68          CONFIG(n("quadrige2.update.config"));
69  
70          private final String i18nKey;
71  
72          UpdateType(String i18nKey) {
73              this.i18nKey = i18nKey;
74          }
75  
76          public String getLabel() {
77              return t(i18nKey);
78          }
79      }
80  
81      protected final ApplicationUIContext context;
82  
83      protected List<UpdateType> types;
84  
85      protected final ProgressionModel progressionModel;
86  
87      protected boolean dataUpdated;
88  
89      protected final AbstractAction<?, ?, ?> action;
90  
91      /**
92       * <p>Constructor for DataUpdaterCallBack.</p>
93       *
94       * @param action a {@link AbstractAction} object.
95       * @param progressionModel a {@link ProgressionModel} object.
96       */
97      public DataUpdaterCallBack(AbstractAction<?, ?, ?> action, ProgressionModel progressionModel) {
98          this.action = action;
99          this.context = action.getContext();
100         this.progressionModel = progressionModel;
101     }
102 
103     /**
104      * <p>Setter for the field <code>types</code>.</p>
105      *
106      * @param types a {@link DataUpdaterCallBack.UpdateType} object.
107      */
108     public void setTypes(UpdateType... types) {
109         this.types = Lists.newArrayList(types);
110     }
111 
112     /**
113      * <p>isDataUpdated.</p>
114      *
115      * @return a boolean.
116      */
117     public boolean isDataUpdated() {
118         return dataUpdated;
119     }
120 
121     /** {@inheritDoc} */
122     @Override
123     public Map<String, ApplicationInfo> updateToDo(Map<String, ApplicationInfo> appToUpdate) {
124         Map<String, ApplicationInfo> result = Maps.newHashMap();
125 
126         for (UpdateType type : types) {
127             ApplicationInfo info = getInfo(type, appToUpdate);
128             if (info != null) {
129                 result.put(info.name, info);
130             }
131         }
132         return result;
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     public void startUpdate(ApplicationInfo info) {
138         if (UpdateType.I18N.name().toLowerCase().equals(info.name)) {
139             progressionModel.setMessage(t("quadrige2.applicationUpdater.startUpdate.i18n", info.newVersion));
140         }
141         if (UpdateType.HELP.name().toLowerCase().equals(info.name)) {
142             progressionModel.setMessage(t("quadrige2.applicationUpdater.startUpdate.help", info.newVersion));
143         }
144         if (UpdateType.CONFIG.name().toLowerCase().equals(info.name)) {
145             progressionModel.setMessage(t("quadrige2.applicationUpdater.startUpdate.config", info.newVersion));
146         }
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public void updateDone(Map<String, ApplicationInfo> appToUpdate,
152         Map<String, Exception> appUpdateError) {
153 
154         boolean updateI18n = updateDoneI18n(appToUpdate, appUpdateError);
155         boolean updateHelp = updateDoneHelp(appToUpdate, appUpdateError);
156         boolean updateConfig = updateDoneConfig(appToUpdate, appUpdateError);
157 
158         boolean doRestart = updateI18n || updateHelp || updateConfig;
159 
160         if (doRestart) {
161             dataUpdated = true;
162         }
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public void aborted(String propertiesURL, Exception eee) {
168         if (LOG.isErrorEnabled()) {
169             LOG.error("Could not update from " + propertiesURL, eee);
170         }
171         throw ApplicationActionException.propagateError(action, eee);
172     }
173 
174     /**
175      * <p>updateDoneI18n.</p>
176      *
177      * @param appToUpdate a {@link Map} object.
178      * @param appUpdateError a {@link Map} object.
179      * @return a boolean.
180      */
181     protected boolean updateDoneI18n(Map<String, ApplicationInfo> appToUpdate, Map<String, Exception> appUpdateError) {
182         boolean doRestart = false;
183         Exception error = getError(UpdateType.I18N, appUpdateError);
184         if (error != null) {
185 
186             // something bad while updating i18n
187             throw ApplicationActionException.propagateError(
188                 action, new ApplicationTechnicalException(t("quadrige2.applicationUpdater.i18n.error"), error));
189         }
190         ApplicationInfo info = getInfo(UpdateType.I18N, appToUpdate);
191         if (info != null) {
192 
193             if (LOG.isInfoEnabled()) {
194                 LOG.info(String.format(
195                     "A i18n update was downloaded (oldVersion: %s, newVersion: %s), will restart application to use it",
196                     info.oldVersion, info.newVersion));
197             }
198             doRestart = true;
199         }
200         return doRestart;
201     }
202 
203     /**
204      * <p>updateDoneHelp.</p>
205      *
206      * @param appToUpdate a {@link Map} object.
207      * @param appUpdateError a {@link Map} object.
208      * @return a boolean.
209      */
210     protected boolean updateDoneHelp(Map<String, ApplicationInfo> appToUpdate, Map<String, Exception> appUpdateError) {
211         boolean doRestart = false;
212         Exception error = getError(UpdateType.HELP, appUpdateError);
213         if (error != null) {
214 
215             // something bad while updating help
216             throw ApplicationActionException.propagateError(
217                 action, new ApplicationTechnicalException(t("quadrige2.applicationUpdater.help.error"), error));
218         }
219         ApplicationInfo info = getInfo(UpdateType.HELP, appToUpdate);
220         if (info != null) {
221 
222             if (LOG.isInfoEnabled()) {
223                 LOG.info(String.format(
224                     "A help update was downloaded (oldVersion: %s, newVersion: %s), will restart application to use it",
225                     info.oldVersion, info.newVersion));
226             }
227             doRestart = true;
228 
229         }
230         return doRestart;
231     }
232 
233     /**
234      * <p>updateDoneConfig.</p>
235      *
236      * @param appToUpdate a {@link Map} object.
237      * @param appUpdateError a {@link Map} object.
238      * @return a boolean.
239      */
240     protected boolean updateDoneConfig(Map<String, ApplicationInfo> appToUpdate,
241         Map<String, Exception> appUpdateError) {
242         boolean doRestart = false;
243         Exception error = getError(UpdateType.CONFIG, appUpdateError);
244         if (error != null) {
245 
246             // something bad while updating config
247             throw ApplicationActionException.propagateError(
248                 action, new ApplicationTechnicalException(t("quadrige2.applicationUpdater.config.error"), error));
249         }
250         ApplicationInfo info = getInfo(UpdateType.CONFIG, appToUpdate);
251         if (info != null) {
252 
253             if (LOG.isInfoEnabled()) {
254                 LOG.info(String.format(
255                     "A config update was downloaded (oldVersion: %s, newVersion: %s), will process it and application will restart",
256                     info.oldVersion, info.newVersion));
257             }
258             doRestart = true;
259 
260             // Get the new config file
261             try {
262 
263                 // Load file
264                 Properties p = new Properties();
265                 File f = new File(info.destDir, "config/" + context.getConfiguration().getApplicationConfig().getConfigFileName());
266                 p.load(Files.newReader(f, Charsets.UTF_8));
267 
268                 // Updates or create missing properties and save all
269                 context.getConfiguration().overridesOptions(p);
270                 context.getConfiguration().save();
271 
272                 // Create local version.appup
273                 ApplicationUpdater.createVersionFile(context.getConfiguration().getConfigDirectory(), info.newVersion);
274 
275             } catch (IOException ex) {
276                 throw ApplicationActionException.propagateError(
277                     action, new ApplicationTechnicalException(t("quadrige2.applicationUpdater.config.io.error"), ex));
278             }
279         }
280         return doRestart;
281     }
282 
283     /**
284      * <p>getInfo.</p>
285      *
286      * @param type a {@link DataUpdaterCallBack.UpdateType} object.
287      * @param appToUpdate a {@link Map} object.
288      * @return a {@link ApplicationInfo} object.
289      */
290     protected ApplicationInfo getInfo(UpdateType type, Map<String, ApplicationInfo> appToUpdate) {
291         return appToUpdate.get(type.name().toLowerCase());
292     }
293 
294     /**
295      * <p>getError.</p>
296      *
297      * @param type a {@link DataUpdaterCallBack.UpdateType} object.
298      * @param appUpdateError a {@link Map} object.
299      * @return a {@link Exception} object.
300      */
301     protected Exception getError(UpdateType type, Map<String, Exception> appUpdateError) {
302         return appUpdateError.get(type.name().toLowerCase());
303     }
304 }