1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package fr.cnes.doi.settings;
20
21 import fr.cnes.doi.exception.DoiRuntimeException;
22 import fr.cnes.doi.plugin.PluginFactory;
23 import fr.cnes.doi.security.UtilsCryptography;
24 import fr.cnes.doi.server.Starter;
25 import fr.cnes.doi.utils.DOIProperties;
26 import fr.cnes.doi.utils.Utils;
27 import fr.cnes.doi.utils.spec.Requirement;
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.OutputStream;
33 import java.io.UnsupportedEncodingException;
34 import java.net.URLDecoder;
35 import java.util.Enumeration;
36 import java.util.Map.Entry;
37 import java.util.Properties;
38 import java.util.concurrent.ConcurrentHashMap;
39 import org.apache.logging.log4j.Level;
40 import org.apache.logging.log4j.LogManager;
41 import org.apache.logging.log4j.Logger;
42 import org.restlet.data.LocalReference;
43 import org.restlet.representation.Representation;
44 import org.restlet.resource.ClientResource;
45
46
47
48
49
50
51 @Requirement(reqId = Requirement.DOI_CONFIG_010, reqName = Requirement.DOI_CONFIG_010_NAME)
52 public final class DoiSettings {
53
54
55
56
57 public static final String CONFIG_PROPERTIES = "config.properties";
58
59
60
61
62 private static final Logger LOG = LogManager.getLogger(DoiSettings.class.getName());
63
64
65
66
67 private static final String INIST_TEST_DOI = "10.5072";
68
69
70
71
72 private static final ConcurrentHashMap<String, String> MAP_PROPERTIES = new ConcurrentHashMap<>();
73
74
75
76
77
78
79 public static DoiSettings getInstance() {
80 LOG.traceEntry();
81 return LOG.traceExit(DoiSettingsHolder.INSTANCE);
82 }
83
84
85
86
87 private String secretKey = UtilsCryptography.DEFAULT_SECRET_KEY;
88
89
90
91
92 private String pathApp;
93
94
95
96
97
98 private DoiSettings() {
99 final Properties properties = loadConfigurationFile();
100 init(properties, Level.OFF);
101 }
102
103
104
105
106
107
108
109 private void init(final Properties properties, Level level) {
110 if (Level.OFF.equals(level)) {
111 level = null;
112 }
113 LOG.traceEntry("Parameter\n\tproperties:{}\n\tlevel:{}", properties, level);
114 LOG.log(level, "----- DOI parameters ----");
115 fillConcurrentMap(properties, level);
116 computePathOfTheApplication();
117 PluginFactory.init(DoiSettings.MAP_PROPERTIES);
118 final Enumeration<String> keys = DoiSettings.MAP_PROPERTIES.keys();
119 while (keys.hasMoreElements()) {
120 final String key = keys.nextElement();
121 LOG.log(
122 level, "{} = {}",
123 key,
124 isPassword(String.valueOf(key))
125 ? Utils.transformPasswordToStars(String.valueOf(DoiSettings.MAP_PROPERTIES.get(
126 key)))
127 : DoiSettings.MAP_PROPERTIES.get(key)
128 );
129 }
130 LOG.log(level, "DOI settings have been loaded");
131 LOG.log(level, "-------------------------");
132 LOG.log(level, properties.getProperty(Consts.NAME) + " loaded");
133 LOG.traceExit();
134 }
135
136
137
138
139 private void computePathOfTheApplication() {
140 LOG.traceEntry();
141 try {
142 final String path = Starter.class.getProtectionDomain().getCodeSource().getLocation().
143 getPath();
144 String decodedPath = URLDecoder.decode(path, "UTF-8");
145 final int posLastSlash = decodedPath.lastIndexOf('/');
146 decodedPath = decodedPath.substring(0, posLastSlash);
147 this.pathApp = decodedPath;
148 } catch (UnsupportedEncodingException ex) {
149 throw LOG.throwing(new DoiRuntimeException(ex));
150 }
151 LOG.traceExit();
152 }
153
154
155
156
157
158
159 private Properties loadConfigurationFile() {
160 LOG.traceEntry();
161 final Properties properties = new DOIProperties();
162 final ClientResource client = new ClientResource(LocalReference.createClapReference(
163 "class/config.properties"));
164 final Representation configurationFile = client.get();
165 try {
166 LOG.debug("Loading " + CONFIG_PROPERTIES + " by default");
167 properties.load(configurationFile.getStream());
168 } catch (IOException e) {
169 LOG.fatal("Unable to load " + CONFIG_PROPERTIES);
170 throw LOG.throwing(new DoiRuntimeException("Unable to load class/config.properties", e));
171 } finally {
172 client.release();
173 }
174 return LOG.traceExit(properties);
175 }
176
177
178
179
180 public void validConfigurationFile() {
181 LOG.traceEntry();
182 final StringBuilder validation = new StringBuilder();
183 final String message = "Sets ";
184 if (isNotExist(DoiSettings.MAP_PROPERTIES, Consts.INIST_DOI)) {
185 validation.append(message).append(Consts.INIST_DOI).append("\n");
186 }
187 if (isNotExist(DoiSettings.MAP_PROPERTIES, Consts.INIST_LOGIN)) {
188 validation.append(message).append(Consts.INIST_LOGIN).append("\n");
189 }
190 if (isNotExist(DoiSettings.MAP_PROPERTIES, Consts.INIST_PWD)) {
191 validation.append(message).append(Consts.INIST_PWD).append("\n");
192 }
193 if (isNotExist(DoiSettings.MAP_PROPERTIES, Consts.SERVER_PROXY_TYPE)) {
194 validation.append(message).append(Consts.SERVER_PROXY_TYPE).append("\n");
195 }
196 if (isNotExist(DoiSettings.MAP_PROPERTIES, Consts.PLUGIN_PROJECT_SUFFIX)) {
197 validation.append(message).append(Consts.PLUGIN_PROJECT_SUFFIX).append("\n");
198 }
199 if (isNotExist(DoiSettings.MAP_PROPERTIES, Consts.PLUGIN_TOKEN)) {
200 validation.append(message).append(Consts.PLUGIN_TOKEN).append("\n");
201 }
202 if (isNotExist(DoiSettings.MAP_PROPERTIES, Consts.PLUGIN_USER_GROUP_MGT)) {
203 validation.append(message).append(Consts.PLUGIN_USER_GROUP_MGT).append("\n");
204 }
205
206 if (isNotExist(DoiSettings.MAP_PROPERTIES, Consts.PLUGIN_AUTHENTICATION)) {
207 validation.append(message).append(Consts.PLUGIN_AUTHENTICATION).append("\n");
208 }
209
210 validation.append(PluginFactory.getAuthenticationSystem().validate());
211 validation.append(PluginFactory.getProjectSuffix().validate());
212 validation.append(PluginFactory.getToken().validate());
213 validation.append(PluginFactory.getUserManagement().validate());
214
215 if (validation.length() != 0) {
216 throw LOG.traceExit(new DoiRuntimeException(validation.toString()));
217 }
218 LOG.traceExit();
219 }
220
221
222
223
224
225
226
227
228 private boolean isExist(final ConcurrentHashMap<String, String> properties,
229 final String keyword) {
230 LOG.traceEntry("Parameters\n\tproperties : {}\n\tkeyword : {}", properties, keyword);
231 return LOG.traceExit(properties.containsKey(keyword) && !properties.get(keyword).isEmpty());
232 }
233
234
235
236
237
238
239
240
241
242 private boolean isNotExist(final ConcurrentHashMap<String, String> properties,
243 final String keyword) {
244 LOG.traceEntry("Parameters\n\tproperties : {}\n\tkeyword : {}", properties, keyword);
245 return LOG.traceExit(!isExist(properties, keyword));
246 }
247
248
249
250
251
252
253
254 private void fillConcurrentMap(final Properties properties, final Level level) {
255 LOG.traceEntry("Parameters\n\tproperties : {}\n\tlevel : {}", properties, level);
256 for (final Entry<Object, Object> entry : properties.entrySet()) {
257 MAP_PROPERTIES.put((String) entry.getKey(), (String) entry.getValue());
258 }
259 LOG.traceExit();
260 }
261
262
263
264
265
266
267
268 private boolean isPassword(final String key) {
269 LOG.traceEntry("Parameter\n\tkey:{}", key);
270 return LOG.traceExit(Consts.INIST_PWD.equals(key)
271 || PluginFactory.isPassword(Consts.PLUGIN_AUTHENTICATION, key)
272 || PluginFactory.isPassword(Consts.PLUGIN_PROJECT_SUFFIX, key)
273 || PluginFactory.isPassword(Consts.PLUGIN_TOKEN, key)
274 || PluginFactory.isPassword(Consts.PLUGIN_USER_GROUP_MGT, key)
275 || Consts.SERVER_HTTPS_KEYSTORE_PASSWD.equals(key)
276 || Consts.SERVER_HTTPS_SECRET_KEY.equals(key) || Consts.SERVER_PROXY_PWD.equals(key)
277 || Consts.SMTP_AUTH_PWD.equals(key) || Consts.TOKEN_KEY.equals(key));
278 }
279
280
281
282
283
284
285
286 public boolean hasValue(final String key) {
287 LOG.traceEntry("Parameter\n\tkey : {}", key);
288 return LOG.traceExit(Utils.isNotEmpty(getString(key)));
289 }
290
291
292
293
294
295
296 public String getSecretKey() {
297 LOG.traceEntry();
298 return LOG.traceExit(this.secretKey);
299 }
300
301
302
303
304
305
306 public void setSecretKey(final String secretKey) {
307 LOG.traceEntry("Parameter\n\t secretKey : {}", secretKey);
308 this.secretKey = secretKey;
309 LOG.traceExit();
310 }
311
312
313
314
315
316
317
318
319 public String getString(final String key, final String defaultValue) {
320 LOG.traceEntry("Parameters\n\tkey : {}\n\tdefaultValue : {}", key, defaultValue);
321 return LOG.traceExit(MAP_PROPERTIES.getOrDefault(key, defaultValue));
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337 public String getString(final String key) {
338 LOG.traceEntry("Parameter\n\tkey : {}", key);
339 final String value;
340 if (Consts.INIST_DOI.equals(key)) {
341 final String context = this.getString(Consts.CONTEXT_MODE, "DEV");
342 value = "PRE_PROD".equals(context) ? INIST_TEST_DOI : this.getString(Consts.INIST_DOI,
343 null);
344 } else {
345 value = this.getString(key, null);
346 }
347 return LOG.traceExit(value);
348 }
349
350
351
352
353
354
355
356
357 public String getSecret(final String key) {
358 LOG.traceEntry("Parameter\n\tkey : {}", key);
359 final String result;
360 final String value = getString(key, "");
361 final boolean isEncrypted = Boolean.parseBoolean(
362 this.getString(Consts.ENCRYPTED_FIELDS, "true"));
363 if (Utils.isEmpty(value)) {
364 result = value;
365 } else if (isEncrypted) {
366 result = UtilsCryptography.decrypt(value, getSecretKey());
367 } else {
368 result = value;
369 }
370 return LOG.traceExit(result);
371 }
372
373
374
375
376
377
378
379
380 public String getSecretValue(final String value) {
381 LOG.traceEntry("Parameter\n\tvalue : {}", value);
382 final String result;
383 final boolean isEncrypted = Boolean.parseBoolean(
384 this.getString(Consts.ENCRYPTED_FIELDS, "true"));
385 if (Utils.isEmpty(value)) {
386 result = value;
387 } else if (isEncrypted) {
388 result = UtilsCryptography.decrypt(value, getSecretKey());
389 } else {
390 result = value;
391 }
392 return LOG.traceExit(result);
393 }
394
395
396
397
398
399
400
401
402
403
404
405 public int getInt(final String key) {
406 LOG.traceEntry("Parameter\n\tkey : {}", key);
407 return LOG.traceExit(Integer.parseInt(getString(key)));
408 }
409
410
411
412
413
414
415
416
417
418
419
420 public int getInt(final String key, final String defaultValue) {
421 LOG.traceEntry("Parameter\n\tkey : {}\n\tdefaultValue", key, defaultValue);
422 return LOG.traceExit(Integer.parseInt(getString(key, defaultValue)));
423 }
424
425
426
427
428
429
430
431
432
433 public boolean getBoolean(final String key) {
434 LOG.traceEntry("Parameter\n\tkey : {}", key);
435 if (getString(key) == null) {
436 throw LOG.throwing(Level.TRACE, new IllegalArgumentException("Key not found : " + key));
437 } else {
438 return LOG.traceExit(Boolean.parseBoolean(getString(key)));
439 }
440 }
441
442
443
444
445
446
447
448
449
450
451 public Long getLong(final String key) {
452 LOG.traceEntry("Parameter\n\tkey : {}", key);
453 return LOG.traceExit(Long.parseLong(getString(key)));
454 }
455
456
457
458
459
460
461
462
463
464
465
466 public Long getLong(final String key, final String defaultValue) {
467 LOG.traceEntry("Parameter\n\tkey : {}\n\tdefaultValue", key, defaultValue);
468 return LOG.traceExit(Long.parseLong(getString(key, defaultValue)));
469 }
470
471
472
473
474 public void displayConfigFile() {
475 LOG.traceEntry();
476 final ClientResource client = new ClientResource(LocalReference.createClapReference(
477 "class/" + CONFIG_PROPERTIES));
478 final Representation configurationFile = client.get();
479 try {
480 copyStream(configurationFile.getStream(), System.out);
481 } catch (IOException ex) {
482 LOG.fatal("Cannot display the configuration file located to class/" + CONFIG_PROPERTIES,
483 ex);
484 } finally {
485 client.release();
486 }
487 LOG.traceExit();
488 }
489
490
491
492
493
494
495
496
497 public void setPropertiesFile(final String path) throws IOException {
498 LOG.traceEntry("Parameter\n\tpath : {}", path);
499 try (InputStream inputStream = new FileInputStream(new File(path))) {
500 setPropertiesFile(inputStream);
501 }
502 LOG.traceExit();
503 }
504
505
506
507
508
509
510
511
512 public void setPropertiesFile(final InputStream inputStream) throws IOException {
513 LOG.traceEntry("With an inputstream");
514 final Properties properties = new DOIProperties();
515 properties.load(inputStream);
516 init(properties, Level.INFO);
517
518
519
520 ProxySettings.getInstance().init();
521 EmailSettings.getInstance().init();
522 LOG.traceExit();
523 }
524
525
526
527
528
529
530 public String getPathApp() {
531 LOG.traceEntry();
532 return LOG.traceExit(this.pathApp);
533 }
534
535
536
537
538
539
540
541 private void copyStream(final InputStream inputStream, final OutputStream outputStream) {
542 LOG.traceEntry("With an input and output stream");
543 final int bufferSize = 1024;
544 try {
545 final byte[] bytes = new byte[bufferSize];
546 for (;;) {
547 final int count = inputStream.read(bytes, 0, bufferSize);
548 if (count == -1) {
549 break;
550 }
551 outputStream.write(bytes, 0, count);
552 }
553 inputStream.close();
554 outputStream.flush();
555 outputStream.close();
556 } catch (IOException ex) {
557 LOG.fatal("error when displaying the configuraiton file on the standard output", ex);
558 }
559 LOG.traceExit();
560 }
561
562
563
564
565 private static class DoiSettingsHolder {
566
567
568
569
570 private static final DoiSettings INSTANCE = new DoiSettings();
571 }
572 }