View Javadoc
1   package fr.ifremer.quadrige3.core.config;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 Client Core
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  import com.google.common.base.Joiner;
26  import com.google.common.base.Splitter;
27  import com.google.common.collect.Sets;
28  import fr.ifremer.common.synchro.config.SynchroConfiguration;
29  import fr.ifremer.common.synchro.config.SynchroConfigurationOption;
30  import fr.ifremer.quadrige3.core.dao.technical.Beans;
31  import fr.ifremer.quadrige3.core.dao.technical.Daos;
32  import fr.ifremer.quadrige3.core.dao.technical.Files;
33  import fr.ifremer.quadrige3.core.security.SecurityContextHelper;
34  import fr.ifremer.quadrige3.synchro.meta.DatabaseColumns;
35  import org.apache.commons.lang3.StringUtils;
36  import org.apache.commons.logging.Log;
37  import org.apache.commons.logging.LogFactory;
38  import org.nuiton.config.ApplicationConfig;
39  import org.nuiton.config.ApplicationConfigHelper;
40  import org.nuiton.config.ApplicationConfigProvider;
41  import org.nuiton.config.ArgumentsParserException;
42  import org.nuiton.jaxx.application.ApplicationConfiguration;
43  import org.nuiton.jaxx.application.ApplicationIOUtil;
44  import org.nuiton.jaxx.application.ApplicationTechnicalException;
45  import org.springframework.beans.factory.InitializingBean;
46  import org.springframework.util.CollectionUtils;
47  
48  import javax.swing.KeyStroke;
49  import java.awt.Color;
50  import java.io.File;
51  import java.io.IOException;
52  import java.net.MalformedURLException;
53  import java.net.URL;
54  import java.nio.charset.StandardCharsets;
55  import java.util.*;
56  import java.util.stream.Collectors;
57  
58  import static org.nuiton.i18n.I18n.t;
59  
60  /**
61   * @author peck7 on 29/06/2017.
62   */
63  public abstract class QuadrigeCoreConfiguration extends ApplicationConfiguration implements InitializingBean {
64  
65      private static final Log LOG = LogFactory.getLog(QuadrigeCoreConfiguration.class);
66  
67      private static QuadrigeCoreConfiguration instance;
68      private final Set<String> optionKeyToNotSave = Sets.newHashSet();
69      private File configFile;
70  
71      public QuadrigeCoreConfiguration(ApplicationConfig applicationConfig) {
72          super(applicationConfig);
73          prepareDirectories();
74      }
75  
76      public QuadrigeCoreConfiguration(String file, String... args) {
77          super(new QuadrigeApplicationConfig());
78  
79          // Set general encoding
80          applicationConfig.setEncoding(StandardCharsets.UTF_8.name());
81          // Set config file name
82          applicationConfig.setConfigFileName(file);
83  
84          // get all config providers (declaring Java 6 SPI)
85          loadProviders();
86  
87          // Add alias
88          addAlias(applicationConfig);
89  
90          try {
91              applicationConfig.parse(args);
92  
93          } catch (ArgumentsParserException e) {
94              throw new ApplicationTechnicalException(t("quadrige3.config.parse.error"), e);
95          }
96  
97          // Override some external module default config (quadrige3)
98          overrideExternalModulesDefaultOptions();
99  
100         // Give the same applicationConfig to quadrige3
101         QuadrigeConfiguration quadrigeConfig = new QuadrigeConfiguration(applicationConfig);
102         QuadrigeConfiguration.setInstance(quadrigeConfig);
103 
104         // Give the same applicationConfig to synchro
105         SynchroConfiguration synchroConfig = new SynchroConfiguration(applicationConfig);
106         SynchroConfiguration.setInstance(synchroConfig);
107 
108     }
109 
110     private void loadProviders() {
111 
112         // get all config providers (declaring Java 6 SPI)
113         Set<ApplicationConfigProvider> providers = ApplicationConfigHelper.getProviders(null, null, null, true);
114 
115         // load all default options
116         ApplicationConfigHelper.loadAllDefaultOption(applicationConfig, providers);
117 
118         // Load actions
119         for (ApplicationConfigProvider provider : providers) {
120             applicationConfig.loadActions(provider.getActions());
121         }
122 
123         // get all transient and final option keys
124         Set<String> optionToSkip = ApplicationConfigHelper.getTransientOptionKeys(providers);
125 
126         if (LOG.isDebugEnabled()) {
127             LOG.debug("Option that won't be saved: " + optionToSkip);
128         }
129         optionKeyToNotSave.addAll(optionToSkip);
130 
131     }
132 
133     public static QuadrigeCoreConfiguration getInstance() {
134         return instance;
135     }
136 
137     public static void setInstance(QuadrigeCoreConfiguration instance) {
138         QuadrigeCoreConfiguration.instance = instance;
139     }
140 
141     protected void overrideExternalModulesDefaultOptions() {
142 
143         // Map synchro.persistence.XXX to quadrige3.persistence.XXX
144         QuadrigeConfigurations.remapOptionsToPrefix(applicationConfig,
145                 "synchro.persistence",
146                 QuadrigeConfigurationOption.values(),
147                 "quadrige3.persistence");
148 
149         // Map synchro.XXX to quadrige3.synchro.XXX
150         QuadrigeConfigurations.remapOptionsToPrefix(applicationConfig,
151                 "synchro",
152                 QuadrigeConfigurationOption.values(),
153                 "quadrige3.synchro");
154 
155         applicationConfig.setDefaultOption(SynchroConfigurationOption.TEMP_QUERY_PARAMETER_USER_ID.getKey(),
156                 DatabaseColumns.QUSER_ID.name());
157     }
158 
159     /**
160      * Add alias to the given ApplicationConfig. <p/>
161      * This method could be override to add specific alias
162      *
163      * @param applicationConfig a {@link org.nuiton.config.ApplicationConfig} object.
164      */
165     protected void addAlias(ApplicationConfig applicationConfig) {
166         applicationConfig.addAlias("-db", "--option", QuadrigeConfigurationOption.JDBC_URL.getKey());
167         applicationConfig.addAlias("--database", "--option", QuadrigeConfigurationOption.JDBC_URL.getKey());
168         applicationConfig.addAlias("--output", "--option", QuadrigeConfigurationOption.LIQUIBASE_OUTPUT_FILE.getKey());
169     }
170 
171     @Override
172     public KeyStroke getShortcutClosePopup() {
173         return null;
174     }
175 
176     @Override
177     public void afterPropertiesSet() {
178         prepareDirectories();
179     }
180 
181     protected void prepareDirectories() {
182 
183         File directory = getDataDirectory();
184         ApplicationIOUtil.forceMkdir(directory, t("quadrige3.error.create.directory", directory));
185 
186         directory = getDbDirectory();
187         ApplicationIOUtil.forceMkdir(directory, t("quadrige3.error.create.directory", directory));
188 
189         directory = getDbAttachmentDirectory();
190         ApplicationIOUtil.forceMkdir(directory, t("quadrige3.error.create.directory", directory));
191 
192         directory = getDbPhotoDirectory();
193         ApplicationIOUtil.forceMkdir(directory, t("quadrige3.error.create.directory", directory));
194 
195         directory = getDbBackupDirectory();
196         ApplicationIOUtil.forceMkdir(directory, t("quadrige3.error.create.directory", directory));
197 
198 //        directory = getPluginsDirectory();
199 //        ApplicationIOUtil.forceMkdir(directory, t("quadrige3.error.create.directory", directory));
200 
201         directory = getConfigDirectory();
202         ApplicationIOUtil.forceMkdir(directory, t("quadrige3.error.create.directory", directory));
203 
204         directory = getTempDirectory();
205         if (directory.exists()) {
206             Files.cleanDirectory(directory, t("quadrige3.error.delete.directory", directory));
207         }
208         ApplicationIOUtil.forceMkdir(directory, t("quadrige3.error.create.directory", directory));
209 
210     }
211 
212     /*
213      * Database
214      */
215     public File getBaseDirectory() {
216         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.BASEDIR.getKey());
217     }
218 
219     public File getLockFile() {
220         return new File(getBaseDirectory(), "application.lock");
221     }
222 
223     public File getDataDirectory() {
224         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.DATA_DIRECTORY.getKey());
225     }
226 
227     public File getDbDirectory() {
228         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.DB_DIRECTORY.getKey());
229     }
230 
231     public String getDbName() {
232         return applicationConfig.getOption(QuadrigeConfigurationOption.DB_NAME.getKey());
233     }
234 
235     public String getDbValidationQuery() {
236         return applicationConfig.getOption(QuadrigeConfigurationOption.DB_VALIDATION_QUERY.getKey());
237     }
238 
239     public File getDbAttachmentDirectory() {
240         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.DB_ATTACHMENT_DIRECTORY.getKey());
241     }
242 
243     public File getDbPhotoDirectory() {
244         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.DB_PHOTO_DIRECTORY.getKey());
245     }
246 
247     public File getDbBackupDirectory() {
248         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.DB_BACKUP_DIRECTORY.getKey());
249     }
250 
251     public File getCacheDirectory() {
252         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.DB_CACHE_DIRECTORY.getKey());
253     }
254 
255     public File getI18nDirectory() {
256         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.I18N_DIRECTORY.getKey());
257     }
258 
259 //    public File getPluginsDirectory() {
260 //        return applicationConfig.getOptionAsFile(QuadrigeCoreConfigurationOption.PLUGINS_DIRECTORY.getKey());
261 //    }
262 
263     public File getConfigDirectory() {
264         return applicationConfig.getOptionAsFile(QuadrigeCoreConfigurationOption.CONFIG_DIRECTORY.getKey());
265     }
266 
267     public File getExtractionDirectory() {
268         return applicationConfig.getOptionAsFile(QuadrigeCoreConfigurationOption.EXTRACTION_DIRECTORY.getKey());
269     }
270 
271     public File getExtractionConfigDirectory() {
272         return applicationConfig.getOptionAsFile(QuadrigeCoreConfigurationOption.EXTRACTION_CONFIG_DIRECTORY.getKey());
273     }
274 
275     public File getContextDirectory() {
276         return applicationConfig.getOptionAsFile(QuadrigeCoreConfigurationOption.CONTEXT_DIRECTORY.getKey());
277     }
278 
279     public File getMeasurementGridPresetsDirectory() {
280         return applicationConfig.getOptionAsFile(QuadrigeCoreConfigurationOption.MEASUREMENT_GRID_PRESETS_DIRECTORY.getKey());
281     }
282 
283     public Set<File> getDbOtherDirectories() {
284         String configOption = applicationConfig.getOption(QuadrigeCoreConfigurationOption.DB_OTHER_DIRECTORIES.getKey());
285         return StringUtils.isNotBlank(configOption)
286                 ? Beans.split(configOption, ";").stream().map(File::new).collect(Collectors.toSet())
287                 : new HashSet<>();
288     }
289 
290     public File getTempDirectory() {
291         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.TMP_DIRECTORY.getKey());
292     }
293 
294     public String getJdbcUrl() {
295         return applicationConfig.getOption(QuadrigeConfigurationOption.JDBC_URL.getKey());
296     }
297 
298     public Class<?> getJdbcDriver() {
299         return applicationConfig.getOptionAsClass(QuadrigeConfigurationOption.JDBC_DRIVER.getKey());
300     }
301 
302     public String getJdbcUsername() {
303         return applicationConfig.getOption(QuadrigeConfigurationOption.JDBC_USERNAME.getKey());
304     }
305 
306     public String getJdbcPassword() {
307         return applicationConfig.getOption(QuadrigeConfigurationOption.JDBC_PASSWORD.getKey());
308     }
309 
310     public Class<?> getHibernateDialect() {
311         return applicationConfig.getOptionAsClass(QuadrigeConfigurationOption.HIBERNATE_DIALECT.getKey());
312     }
313 
314     public boolean isHibernateShowSql() {
315         return applicationConfig.getOptionAsBoolean(QuadrigeConfigurationOption.HIBERNATE_SHOW_SQL.getKey());
316     }
317 
318     public boolean isHibernateUseSqlComment() {
319         return applicationConfig.getOptionAsBoolean(QuadrigeConfigurationOption.HIBERNATE_USE_SQL_COMMENT.getKey());
320     }
321 
322     public boolean isHibernateFormatSql() {
323         return applicationConfig.getOptionAsBoolean(QuadrigeConfigurationOption.HIBERNATE_FORMAT_SQL.getKey());
324     }
325 
326     public Properties getConnectionProperties() {
327         return Daos.getConnectionProperties(
328                 getJdbcUrl(),
329                 getJdbcUsername(),
330                 getJdbcPassword(),
331                 null,
332                 getHibernateDialect().getName(),
333                 getJdbcDriver().getName());
334     }
335 
336     public boolean isDbExists() {
337         if (!Daos.isHsqlFileDatabase(getJdbcUrl())) {
338             return true;
339         }
340         File f = new File(getDbDirectory(), getDbName() + ".script");
341         return f.exists();
342     }
343 
344 
345     /*
346      * Update Urls
347      */
348 
349     public String getUpdateApplicationUrl() {
350         return applicationConfig.getOption(QuadrigeCoreConfigurationOption.UPDATE_APPLICATION_URL.getKey());
351     }
352 
353     public String getUpdateDataUrl() {
354         return applicationConfig.getOption(QuadrigeCoreConfigurationOption.UPDATE_DATA_URL.getKey());
355     }
356 
357     public String getInstallDbUrl() {
358         return applicationConfig.getOption(QuadrigeCoreConfigurationOption.INSTALL_DB_URL.getKey());
359     }
360 
361 
362 
363     /*
364      * Authentication 
365      */
366 
367     public boolean isAuthenticationDisabled() {
368         return applicationConfig.getOptionAsBoolean(QuadrigeCoreConfigurationOption.AUTHENTICATION_DISABLED.getKey());
369     }
370 
371     public boolean isAuthenticationForced() {
372         return applicationConfig.getOptionAsBoolean(QuadrigeCoreConfigurationOption.AUTHENTICATION_FORCED.getKey());
373     }
374 
375     public URL getAuthenticationIntranetSiteUrl() {
376         return applicationConfig.getOptionAsURL(QuadrigeCoreConfigurationOption.AUTHENTICATION_INTRANET_SITE_URL.getKey());
377     }
378 
379     public Integer getAuthenticationIntranetSiteTimeout() {
380         return applicationConfig.getOptionAsInt(QuadrigeCoreConfigurationOption.AUTHENTICATION_INTRANET_SITE_TIMEOUT.getKey());
381     }
382 
383     public URL getAuthenticationExtranetSiteUrl() {
384         return applicationConfig.getOptionAsURL(QuadrigeCoreConfigurationOption.AUTHENTICATION_EXTRANET_SITE_URL.getKey());
385     }
386 
387     public Integer getAuthenticationExtranetSiteTimeout() {
388         return applicationConfig.getOptionAsInt(QuadrigeCoreConfigurationOption.AUTHENTICATION_EXTRANET_SITE_TIMEOUT.getKey());
389     }
390 
391     public String getAuthenticationDefaultUsername() {
392         return applicationConfig.getOption(QuadrigeCoreConfigurationOption.AUTHENTICATION_DEFAULT_USERNAME.getKey());
393     }
394 
395     public void setAuthenticationDefaultUsername(String username) {
396         applicationConfig.setOption(QuadrigeCoreConfigurationOption.AUTHENTICATION_DEFAULT_USERNAME.getKey(), username);
397     }
398 
399     public String getAuthenticationDefaultPassword() {
400         return applicationConfig.getOption(QuadrigeCoreConfigurationOption.AUTHENTICATION_DEFAULT_PASSWORD.getKey());
401     }
402 
403     public String getAuthenticationMockUsername() {
404         return applicationConfig.getOption(QuadrigeCoreConfigurationOption.AUTHENTICATION_MOCK_USERNAME.getKey());
405     }
406 
407     public String getAuthenticationMockPassword() {
408         return applicationConfig.getOption(QuadrigeCoreConfigurationOption.AUTHENTICATION_MOCK_PASSWORD.getKey());
409     }
410 
411     public int getAuthenticationMockUserId() {
412         return applicationConfig.getOptionAsInt(QuadrigeCoreConfigurationOption.AUTHENTICATION_MOCK_USER_ID.getKey());
413     }
414 
415     /*
416      * Synchronization
417      */
418 
419     public boolean isSynchronizationUsingServer() {
420         return applicationConfig.getOptionAsBoolean(QuadrigeConfigurationOption.SYNCHRONIZATION_USE_SERVER.getKey());
421     }
422 
423     public URL getSynchronizationSiteUrl() {
424         return getOptionAsURL(QuadrigeConfigurationOption.SYNCHRONIZATION_SITE_URL.getKey());
425     }
426 
427     public Integer getSynchronizationSiteTimeout() {
428         return applicationConfig.getOptionAsInt(QuadrigeConfigurationOption.SYNCHRONIZATION_SITE_TIMEOUT.getKey());
429     }
430 
431     /**
432      * <p>getSynchronizationRefreshTimeout.</p>
433      *
434      * @return a {@link java.lang.Integer} object.
435      */
436     public Integer getSynchronizationRefreshTimeout() {
437         return applicationConfig.getOptionAsInt(QuadrigeConfigurationOption.SYNCHRONIZATION_REFRESH_TIMEOUT.getKey());
438     }
439 
440     /**
441      * <p>getSynchronizationRefreshTimeout.</p>
442      *
443      * @return a {@link java.lang.Integer} object.
444      */
445     public Integer getSynchronizationMaxRetryCount() {
446         return applicationConfig.getOptionAsInt(QuadrigeConfigurationOption.SYNCHRONIZATION_RETRY_COUNT.getKey());
447     }
448 
449     /**
450      * <p>getSynchronizationRetryTimeout.</p>
451      *
452      * @return a {@link java.lang.Integer} object.
453      */
454     public Integer getSynchronizationRetryTimeout() {
455         return applicationConfig.getOptionAsInt(QuadrigeConfigurationOption.SYNCHRONIZATION_RETRY_TIMEOUT.getKey());
456     }
457 
458     public File getSynchronizationDirectory() {
459         return applicationConfig.getOptionAsFile(QuadrigeConfigurationOption.SYNCHRONIZATION_DIRECTORY.getKey());
460     }
461 
462     public boolean isSynchronizationEnabled() {
463         return (/*!isFullLaunchMode() ||*/ !isAuthenticationDisabled()) && getSynchronizationSiteUrl() != null;
464     }
465 
466     public boolean isSynchronizationPeriodSelectionEnable() {
467         return applicationConfig.getOptionAsBoolean(QuadrigeCoreConfigurationOption.SYNCHRONIZATION_PERIOD_SELECTION_ENABLE.getKey());
468     }
469 
470     public String getSynchroZipFilePrefix() {
471         return applicationConfig.getOption(QuadrigeCoreConfigurationOption.SYNCHRONIZATION_ZIP_FILE_PREFIX.getKey());
472     }
473 
474     public File getSynchroUserDirectory() {
475         return new File(getSynchronizationDirectory(), Integer.toString(SecurityContextHelper.getQuadrigeUserId()));
476     }
477 
478     public Set<String> getSynchroProgramCodeIncludes() {
479         String programCodesStr = applicationConfig.getOption(QuadrigeCoreConfigurationOption.SYNCHRO_PROGRAM_CODES_INCLUDES.getKey());
480         if (StringUtils.isBlank(programCodesStr)) {
481             return new HashSet<>();
482         }
483 
484         return Sets.newLinkedHashSet(
485                 Splitter.on(',').trimResults().omitEmptyStrings().split(programCodesStr)
486         );
487     }
488 
489     public void setSynchroProgramCodeIncludes(Set<String> programCodes) {
490         String option = CollectionUtils.isEmpty(programCodes) ? null : Joiner.on(',').join(programCodes);
491         applicationConfig.setOption(QuadrigeCoreConfigurationOption.SYNCHRO_PROGRAM_CODES_INCLUDES.getKey(), option);
492     }
493 
494     public boolean isSynchroPhotoEnabledByDefault() {
495         return applicationConfig.getOptionAsBoolean(QuadrigeCoreConfigurationOption.SYNCHRO_PHOTO_ENABLE_DEFAULT.getKey());
496     }
497 
498     public long getSynchroPhotoMaxSize() {
499         return applicationConfig.getOptionAsLong(QuadrigeCoreConfigurationOption.SYNCHRO_PHOTO_MAX_SIZE.getKey());
500     }
501 
502     public int getSynchroPhotoMaxNumberThreshold() {
503         return applicationConfig.getOptionAsInt(QuadrigeCoreConfigurationOption.SYNCHRO_PHOTO_MAX_NUMBER_THRESHOLD.getKey());
504     }
505 
506     /*
507      * Application options
508      */
509 
510     /**
511      * Mode that enable : UI, automatic open DB, DB and application updated<br/>
512      *
513      * @return true if the full mode is enable
514      */
515     public boolean isFullLaunchMode() {
516         return "full".equals(getLaunchMode());
517     }
518 
519     /**
520      * Mode without UI and without automatic open DB <br/>
521      * Used for batch process (i.e. for backup action)
522      *
523      * @return true if the silent mode is enable
524      */
525     public boolean isSilentLaunchMode() {
526         return "silent".equals(getLaunchMode());
527     }
528 
529     /**
530      * <p>getLaunchMode.</p>
531      *
532      * @return a {@link java.lang.String} object.
533      */
534     public String getLaunchMode() {
535         return applicationConfig.getOption(QuadrigeCoreConfigurationOption.LAUNCH_MODE.getKey());
536     }
537 
538     /**
539      * Get debug mode option
540      * @return true if active
541      */
542     public boolean isDebugMode() {
543         return applicationConfig.getOptionAsBoolean(QuadrigeCoreConfigurationOption.DEBUG_MODE.getKey());
544     }
545 
546     /**
547      * <p>getAdminEmail.</p>
548      *
549      * @return a {@link java.lang.String} object, the admin email.
550      */
551     public String getAdminEmail() {
552         return applicationConfig.getOption(QuadrigeConfigurationOption.ADMIN_EMAIL.getKey());
553     }
554 
555     /**
556      * <p>isShowFullConfigEnabled.</p>
557      *
558      * @return a boolean.
559      */
560     public boolean isShowFullConfigEnabled() {
561         return !isFullLaunchMode();
562     }
563 
564     public Locale getI18nLocale() {
565         return applicationConfig.getOptionAsLocale(QuadrigeCoreConfigurationOption.I18N_LOCALE.getKey());
566     }
567 
568     public void setI18nLocale(Locale locale) {
569         applicationConfig.setOption(QuadrigeCoreConfigurationOption.I18N_LOCALE.getKey(), locale.toString());
570     }
571 
572     public List<String> getSplashScreenRightLogos() {
573         String option = applicationConfig.getOption(QuadrigeCoreConfigurationOption.UI_SPLASH_SCREEN_RIGHT_LOGOS.getKey());
574         return StringUtils.isBlank(option) ? null : Arrays.stream(option.split(",")).collect(Collectors.toList());
575     }
576 
577     public List<String> getSplashScreenLeftLogos() {
578         String option = applicationConfig.getOption(QuadrigeCoreConfigurationOption.UI_SPLASH_SCREEN_LEFT_LOGOS.getKey());
579         return StringUtils.isBlank(option) ? null : Arrays.stream(option.split(",")).collect(Collectors.toList());
580     }
581 
582     /*
583      * Utility methods
584      */
585 
586     public String getCsvSeparator() {
587         return applicationConfig.getOption(QuadrigeConfigurationOption.CSV_SEPARATOR.getKey());
588     }
589 
590     public String getValueSeparator() {
591         return applicationConfig.getOption(QuadrigeConfigurationOption.VALUE_SEPARATOR.getKey());
592     }
593 
594     public String getAttributeSeparator() {
595         return applicationConfig.getOption(QuadrigeConfigurationOption.ATTRIBUTE_SEPARATOR.getKey());
596     }
597 
598     public File newTempFile(String basename) {
599         return new File(getTempDirectory(), basename + "_" + System.nanoTime());
600     }
601 
602     public File getConfigFile() {
603         if (configFile == null) {
604             File dir = getConfigDirectory();
605             if (dir == null || !dir.exists()) {
606                 dir = new File(applicationConfig.getUserConfigDirectory());
607             }
608             File originalConfigFile = new File(applicationConfig.getConfigFileName());
609             configFile = new File(dir, originalConfigFile.getName());
610         }
611         return configFile;
612     }
613 
614     public void overridesOptions(Properties options) {
615 
616         for (String key : options.stringPropertyNames()) {
617             String value = options.getProperty(key);
618             applicationConfig.setOption(key, value);
619         }
620 
621     }
622 
623     protected void addOptionToNotSave(String optionKey) {
624         optionKeyToNotSave.add(optionKey);
625     }
626 
627     public void save() {
628 
629         File file = getConfigFile();
630         if (LOG.isDebugEnabled()) {
631             LOG.debug("Save configuration at: " + file);
632         }
633         try {
634             // Save into local user configuration file
635             applicationConfig.save(file, false, optionKeyToNotSave.toArray(new String[0]));
636         } catch (IOException e) {
637             throw new ApplicationTechnicalException(t("quadrige3.config.save.error", file), e);
638         }
639     }
640 
641     /*
642      * Internal methods
643      */
644 
645     protected URL getOptionAsURL(String key) {
646         String urlString = applicationConfig.getOption(key);
647 
648         // Could be empty (e.g. demo deployment)
649         if (StringUtils.isBlank(urlString)) {
650             return null;
651         }
652 
653         // correct end of the url string
654         if (!urlString.endsWith("/")) {
655             int schemeIndex = urlString.indexOf("://");
656             int firstSlashIndex = urlString.indexOf('/', schemeIndex + 3);
657             boolean addSlash = false;
658             if (firstSlashIndex == -1) {
659                 addSlash = true;
660             } else {
661                 int lastSlashIndex = urlString.lastIndexOf('/');
662                 if (lastSlashIndex > firstSlashIndex) {
663                     addSlash = urlString.indexOf('.', lastSlashIndex) == -1;
664                 }
665             }
666 
667             if (addSlash) {
668                 urlString += '/';
669             }
670         }
671 
672         URL url = null;
673         try {
674             url = new URL(urlString);
675         } catch (MalformedURLException ex) {
676             LOG.error(ex.getLocalizedMessage());
677         }
678 
679         return url;
680     }
681 
682     // TODO
683     public Color getColorBlockingLayer() {
684         return null;
685     }
686 
687 }