View Javadoc
1   package fr.ifremer.dali.service.persistence;
2   
3   /*
4    * #%L
5    * Dali :: Core
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 fr.ifremer.dali.config.DaliConfiguration;
27  import fr.ifremer.dali.dao.administration.program.DaliProgramDao;
28  import fr.ifremer.dali.dao.administration.user.DaliDepartmentDao;
29  import fr.ifremer.dali.dao.administration.user.DaliQuserDao;
30  import fr.ifremer.dali.dao.data.survey.DaliCampaignDao;
31  import fr.ifremer.dali.dao.referential.DaliAnalysisInstrumentDao;
32  import fr.ifremer.dali.dao.referential.DaliReferentialDao;
33  import fr.ifremer.dali.dao.referential.DaliSamplingEquipmentDao;
34  import fr.ifremer.dali.dao.referential.DaliUnitDao;
35  import fr.ifremer.dali.dao.referential.monitoringLocation.DaliMonitoringLocationDao;
36  import fr.ifremer.dali.dao.referential.pmfm.*;
37  import fr.ifremer.dali.dao.referential.taxon.DaliTaxonGroupDao;
38  import fr.ifremer.dali.dao.referential.taxon.DaliTaxonNameDao;
39  import fr.ifremer.dali.dao.system.context.DaliContextDao;
40  import fr.ifremer.dali.dao.technical.Daos;
41  import fr.ifremer.dali.service.DaliServiceLocator;
42  import fr.ifremer.dali.service.StatusFilter;
43  import fr.ifremer.dali.service.system.SystemService;
44  import fr.ifremer.quadrige3.core.ProgressionCoreModel;
45  import fr.ifremer.quadrige3.core.dao.technical.DatabaseSchemaDao;
46  import fr.ifremer.quadrige3.core.exception.DatabaseSchemaUpdateException;
47  import fr.ifremer.quadrige3.core.exception.VersionNotFoundException;
48  import fr.ifremer.quadrige3.core.service.technical.CacheService;
49  import org.apache.commons.logging.Log;
50  import org.apache.commons.logging.LogFactory;
51  import org.nuiton.jaxx.application.ApplicationTechnicalException;
52  import org.nuiton.version.Version;
53  import org.springframework.cache.Cache;
54  import org.springframework.stereotype.Service;
55  
56  import javax.annotation.Resource;
57  import javax.sql.DataSource;
58  import java.time.LocalDate;
59  import java.util.ArrayList;
60  import java.util.List;
61  
62  /**
63   * <p>PersistenceServiceImpl class.</p>
64   *
65   * @author Lionel Touseau <lionel.touseau@e-is.pro>
66   */
67  @Service("daliPersistenceService")
68  public class PersistenceServiceImpl implements PersistenceService {
69  
70      /**
71       * Logger.
72       */
73      private static final Log LOG = LogFactory.getLog(PersistenceServiceImpl.class);
74  
75      @Resource
76      protected CacheService cacheService;
77      @Resource(name = "daliSystemService")
78      protected SystemService systemService;
79      @Resource
80      protected DaliConfiguration config;
81      @Resource
82      protected DatabaseSchemaDao databaseSchemaDao;
83      @Resource(name = "daliContextDao")
84      protected DaliContextDao contextDao;
85      @Resource(name = "daliProgramDao")
86      protected DaliProgramDao programDao;
87      @Resource(name = "daliCampaignDao")
88      protected DaliCampaignDao campaignDao;
89      @Resource(name = "daliQuserDao")
90      protected DaliQuserDao quserDao;
91      @Resource(name = "daliDepartmentDao")
92      protected DaliDepartmentDao departmentDao;
93      @Resource(name = "daliReferentialDao")
94      protected DaliReferentialDao referentialDao;
95      @Resource(name = "daliUnitDao")
96      protected DaliUnitDao unitDao;
97      @Resource(name = "daliMonitoringLocationDao")
98      protected DaliMonitoringLocationDao monitoringLocationDao;
99      @Resource(name = "daliPmfmDao")
100     protected DaliPmfmDao pmfmDao;
101     @Resource(name = "daliParameterDao")
102     protected DaliParameterDao parameterDao;
103     @Resource(name = "daliMatrixDao")
104     protected DaliMatrixDao matrixDao;
105     @Resource(name = "daliFractionDao")
106     protected DaliFractionDao fractionDao;
107     @Resource(name = "daliMethodDao")
108     protected DaliMethodDao methodDao;
109     @Resource(name = "daliTaxonGroupDao")
110     protected DaliTaxonGroupDao taxonGroupDao;
111     @Resource(name = "daliTaxonNameDao")
112     protected DaliTaxonNameDao taxonNameDao;
113     @Resource(name = "daliAnalysisInstrumentDao")
114     private DaliAnalysisInstrumentDao analysisInstrumentDao;
115     @Resource(name = "daliSamplingEquipmentDao")
116     private DaliSamplingEquipmentDao samplingEquipmentDao;
117 
118     /**
119      * {@inheritDoc}
120      */
121     @Override
122     public void afterPropertiesSet() {
123         if (config.isCleanCacheAtStartup()) {
124             clearAllCaches();
125         }
126     }
127 
128     /**
129      * {@inheritDoc}
130      */
131     @Override
132     public void close() {
133         shutdownDatabase();
134     }
135 
136     /**
137      * {@inheritDoc}
138      */
139     @Override
140     public Version getDbVersion() {
141         try {
142             if (!databaseSchemaDao.isDbLoaded()) {
143                 throw new VersionNotFoundException("db is not open");
144             }
145             return databaseSchemaDao.getSchemaVersion();
146         } catch (VersionNotFoundException e) {
147             if (LOG.isErrorEnabled()) {
148                 LOG.error("Could not find db version", e);
149             }
150             return null;
151         }
152     }
153 
154     /**
155      * {@inheritDoc}
156      */
157     @Override
158     public Version getApplicationVersion() {
159         return databaseSchemaDao.getSchemaVersionIfUpdate();
160     }
161 
162     /**
163      * {@inheritDoc}
164      */
165     @Override
166     public void updateSchema() {
167         try {
168             databaseSchemaDao.updateSchema();
169         } catch (DatabaseSchemaUpdateException e) {
170             throw new ApplicationTechnicalException(e);
171         }
172     }
173 
174     /**
175      * {@inheritDoc}
176      */
177     @Override
178     public void compactDb() {
179 
180         if (LOG.isDebugEnabled()) {
181             LOG.debug("Compacting database");
182         }
183 
184         Daos.compactDatabase(getDataSource());
185     }
186 
187     /**
188      * {@inheritDoc}
189      */
190     @Override
191     public void clearAllCaches() {
192         cacheService.clearAllCaches();
193 
194         // wait a while to be sure all caches are cleared
195         try {
196             Thread.sleep(1000);
197         } catch (InterruptedException ignored) {
198         }
199 
200         System.gc();
201     }
202 
203     /**
204      * {@inheritDoc}
205      */
206     @Override
207     public void loadDefaultCaches(ProgressionCoreModel progressionModel) {
208         if (config.isCacheEnabledAtStartup()) {
209 
210             if (LOG.isDebugEnabled()) {
211                 LOG.debug("Loading default caches...");
212             }
213 
214             loadReferentialCaches(progressionModel);
215 
216             if (LOG.isDebugEnabled()) {
217                 LOG.debug("Loading default caches... [OK]");
218             }
219         }
220     }
221 
222     @Override
223     public void enableMassiveUpdate() {
224 
225         if (!Daos.isHsqlFileDatabase(config.getJdbcUrl())) return;
226 
227         if (LOG.isDebugEnabled()) {
228             LOG.debug("Enable massive update behavior [CHECKPOINT first]");
229         }
230 
231         // checkpoint first
232         Daos.sqlUpdate(getDataSource(), "CHECKPOINT");
233 
234         if (LOG.isDebugEnabled()) {
235             LOG.debug("Enable massive update behavior");
236         }
237 
238         // set incremental backup disabled
239         Daos.sqlUpdate(getDataSource(), "SET FILES BACKUP INCREMENT FALSE");
240 
241     }
242 
243     @Override
244     public void disableMassiveUpdate() {
245 
246         if (!Daos.isHsqlFileDatabase(config.getJdbcUrl())) return;
247 
248         if (LOG.isDebugEnabled()) {
249             LOG.debug("Disable massive update behavior [CHECKPOINT first]");
250         }
251 
252         // checkpoint first
253         Daos.sqlUpdate(getDataSource(), "CHECKPOINT");
254 
255         if (LOG.isDebugEnabled()) {
256             LOG.debug("Disable massive update behavior");
257         }
258 
259         // set incremental backup enabled (default)
260         Daos.sqlUpdate(getDataSource(), "SET FILES BACKUP INCREMENT TRUE");
261 
262     }
263 
264     /* -- internal methods -- */
265 
266     /**
267      * <p>loadReferentialCaches.</p>
268      *
269      * @param progressionModel a {@link ProgressionCoreModel} object.
270      */
271     private void loadReferentialCaches(ProgressionCoreModel progressionModel) {
272 
273         List<Runnable> runnables = new ArrayList<>();
274         runnables.add(() -> referentialDao.getAllStatus());
275         runnables.add(() -> contextDao.getAllContext());
276         runnables.add(() -> departmentDao.getAllDepartments(StatusFilter.ACTIVE.toStatusCodes()));
277         runnables.add(() -> quserDao.getAllUsers(StatusFilter.ACTIVE.toStatusCodes()));
278         runnables.add(() -> programDao.getAllPrograms());
279         runnables.add(() -> campaignDao.getAllCampaigns());
280         runnables.add(() -> referentialDao.getAllDepthLevels());
281         runnables.add(() -> referentialDao.getAllGroupingTypes());
282         runnables.add(() -> referentialDao.getAllPositioningSystems());
283         runnables.add(() -> referentialDao.getAllQualityFlags(StatusFilter.ACTIVE.toStatusCodes()));
284         runnables.add(() -> analysisInstrumentDao.getAllAnalysisInstruments(StatusFilter.ACTIVE.toStatusCodes()));
285         runnables.add(() -> samplingEquipmentDao.getAllSamplingEquipments(StatusFilter.ACTIVE.toStatusCodes()));
286         runnables.add(() -> unitDao.getAllUnits(StatusFilter.ACTIVE.toStatusCodes()));
287         runnables.add(() -> monitoringLocationDao.getAllLocations(StatusFilter.ACTIVE.toStatusCodes()));
288         runnables.add(() -> monitoringLocationDao.getAllHarbours(StatusFilter.ACTIVE.toStatusCodes()));
289         runnables.add(() -> parameterDao.getAllParameterGroups(StatusFilter.ACTIVE.toStatusCodes()));
290         runnables.add(() -> parameterDao.getAllParameters(StatusFilter.ACTIVE.toStatusCodes()));
291         runnables.add(() -> matrixDao.getAllMatrices(StatusFilter.ACTIVE.toStatusCodes()));
292         runnables.add(() -> fractionDao.getAllFractions(StatusFilter.ACTIVE.toStatusCodes()));
293         runnables.add(() -> methodDao.getAllMethods(StatusFilter.ACTIVE.toStatusCodes()));
294         runnables.add(() -> pmfmDao.getAllPmfms(StatusFilter.ACTIVE.toStatusCodes()));
295         runnables.add(() -> referentialDao.getAllTaxonomicLevels());
296         runnables.add(() -> taxonNameDao.fillReferents(taxonNameDao.getAllTaxonNames()));
297         runnables.add(() -> {
298             // read previous reference date in taxon group - taxon map
299             Cache cache = cacheService.getCache(DaliTaxonNameDao.TAXON_NAME_BY_TAXON_GROUP_ID_CACHE);
300             if (cache != null && cache.get(LocalDate.now()) == null) {
301                 // if the cache doesn't hold this reference date, clear the taxon groups cache
302                 cacheService.clearCache(DaliTaxonGroupDao.ALL_TAXON_GROUPS_CACHE);
303             }
304             taxonGroupDao.getAllTaxonGroups();
305         });
306 
307         // run all
308         progressionModel.setTotal(runnables.size());
309         runnables.forEach(runnable -> {
310             runnable.run();
311             progressionModel.increments(1);
312         });
313     }
314 
315     /**
316      * <p>shutdownDatabase.</p>
317      */
318     private void shutdownDatabase() {
319         // Do not shutdown if database run as server
320         if (!Daos.isHsqlFileDatabase(config.getJdbcUrl())) {
321             return;
322         }
323 
324         if (LOG.isDebugEnabled()) {
325             LOG.debug("shutting down database");
326         }
327         Daos.shutdownDatabase(getDataSource());
328         if (LOG.isDebugEnabled()) {
329             LOG.debug("database down");
330         }
331     }
332 
333     /**
334      * <p>getDataSource.</p>
335      *
336      * @return a {@link javax.sql.DataSource} object.
337      */
338     protected DataSource getDataSource() {
339         return DaliServiceLocator.instance().getService("dataSource", DataSource.class);
340     }
341 
342 }