%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.commons.configuration.AbstractFileConfiguration |
|
|
1 | /* |
|
2 | * Copyright 2004-2005 The Apache Software Foundation. |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License") |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
15 | */ |
|
16 | ||
17 | package org.apache.commons.configuration; |
|
18 | ||
19 | import java.io.File; |
|
20 | import java.io.FileOutputStream; |
|
21 | import java.io.IOException; |
|
22 | import java.io.InputStream; |
|
23 | import java.io.InputStreamReader; |
|
24 | import java.io.OutputStream; |
|
25 | import java.io.OutputStreamWriter; |
|
26 | import java.io.Reader; |
|
27 | import java.io.UnsupportedEncodingException; |
|
28 | import java.io.Writer; |
|
29 | import java.net.URL; |
|
30 | import java.util.Iterator; |
|
31 | ||
32 | import org.apache.commons.configuration.reloading.InvariantReloadingStrategy; |
|
33 | import org.apache.commons.configuration.reloading.ReloadingStrategy; |
|
34 | import org.apache.commons.lang.StringUtils; |
|
35 | ||
36 | /** |
|
37 | * <p>Partial implementation of the <code>FileConfiguration</code> interface. |
|
38 | * Developpers of file based configuration may want to extend this class, |
|
39 | * the two methods left to implement are <code>{@link FileConfiguration#load(Reader)}</code> |
|
40 | * and <code>{@link FileConfiguration#save(Writer)}.</p> |
|
41 | * <p>This base class already implements a couple of ways to specify the location |
|
42 | * of the file this configuration is based on. The following possibilities |
|
43 | * exist: |
|
44 | * <ul><li>URLs: With the method <code>setURL()</code> a full URL to the |
|
45 | * configuration source can be specified. This is the most flexible way. Note |
|
46 | * that the <code>save()</code> methods support only <em>file:</em> URLs.</li> |
|
47 | * <li>Files: The <code>setFile()</code> method allows to specify the |
|
48 | * configuration source as a file. This can be either a relative or an |
|
49 | * absolute file. In the former case the file is resolved based on the current |
|
50 | * directory.</li> |
|
51 | * <li>As file paths in string form: With the <code>setPath()</code> method a |
|
52 | * full path to a configuration file can be provided as a string.</li> |
|
53 | * <li>Separated as base path and file name: This is the native form in which |
|
54 | * the location is stored. The base path is a string defining either a local |
|
55 | * directory or a URL. It can be set using the <code>setBasePath()</code> |
|
56 | * method. The file name, non surprisingly, defines the name of the configuration |
|
57 | * file.</li></ul></p> |
|
58 | * <p>Note that the <code>load()</code> methods do not wipe out the configuration's |
|
59 | * content before the new configuration file is loaded. Thus it is very easy to |
|
60 | * construct a union configuration by simply loading multiple configuration |
|
61 | * files, e.g.</p> |
|
62 | * <p><pre> |
|
63 | * config.load(configFile1); |
|
64 | * config.load(configFile2); |
|
65 | * </pre></p> |
|
66 | * <p>After executing this code fragment, the resulting configuration will |
|
67 | * contain both the properties of configFile1 and configFile2. On the other |
|
68 | * hand, if the current configuration file is to be reloaded, <code>clear()</code> |
|
69 | * should be called first. Otherwise the properties are doubled. This behavior |
|
70 | * is analogous to the behavior of the <code>load(InputStream)</code> method |
|
71 | * in <code>java.util.Properties</code>.</p> |
|
72 | * |
|
73 | * @author Emmanuel Bourg |
|
74 | * @version $Revision$, $Date: 2005-12-14 20:59:07 +0100 (Wed, 14 Dec 2005) $ |
|
75 | * @since 1.0-rc2 |
|
76 | */ |
|
77 | public abstract class AbstractFileConfiguration extends BaseConfiguration implements FileConfiguration |
|
78 | { |
|
79 | /** Stores the file name.*/ |
|
80 | protected String fileName; |
|
81 | ||
82 | /** Stores the base path.*/ |
|
83 | protected String basePath; |
|
84 | ||
85 | /** The auto save flag.*/ |
|
86 | protected boolean autoSave; |
|
87 | ||
88 | /** Holds a reference to the reloading strategy.*/ |
|
89 | protected ReloadingStrategy strategy; |
|
90 | ||
91 | /** A lock object for protecting reload operations.*/ |
|
92 | 1720 | private Object reloadLock = new Object(); |
93 | ||
94 | /** Stores the encoding of the configuration file.*/ |
|
95 | private String encoding; |
|
96 | ||
97 | /** Stores the URL from which the configuration file was loaded.*/ |
|
98 | private URL sourceURL; |
|
99 | ||
100 | /** A counter that prohibits reloading.*/ |
|
101 | private int noReload; |
|
102 | ||
103 | /** |
|
104 | * Default constructor |
|
105 | * |
|
106 | * @since 1.1 |
|
107 | */ |
|
108 | public AbstractFileConfiguration() |
|
109 | 1720 | { |
110 | 1720 | setReloadingStrategy(new InvariantReloadingStrategy()); |
111 | 1720 | } |
112 | ||
113 | /** |
|
114 | * Creates and loads the configuration from the specified file. The passed |
|
115 | * in string must be a valid file name, either absolute or relativ. |
|
116 | * |
|
117 | * @param fileName The name of the file to load. |
|
118 | * |
|
119 | * @throws ConfigurationException Error while loading the file |
|
120 | * @since 1.1 |
|
121 | */ |
|
122 | public AbstractFileConfiguration(String fileName) throws ConfigurationException |
|
123 | { |
|
124 | 579 | this(); |
125 | ||
126 | // store the file name |
|
127 | 579 | setPath(fileName); |
128 | ||
129 | // load the file |
|
130 | 579 | load(); |
131 | 573 | } |
132 | ||
133 | /** |
|
134 | * Creates and loads the configuration from the specified file. |
|
135 | * |
|
136 | * @param file The file to load. |
|
137 | * @throws ConfigurationException Error while loading the file |
|
138 | * @since 1.1 |
|
139 | */ |
|
140 | public AbstractFileConfiguration(File file) throws ConfigurationException |
|
141 | { |
|
142 | 15 | this(); |
143 | ||
144 | // set the file and update the url, the base path and the file name |
|
145 | 15 | setFile(file); |
146 | ||
147 | // load the file |
|
148 | 15 | if (file.exists()) |
149 | { |
|
150 | 12 | load(); |
151 | } |
|
152 | 12 | } |
153 | ||
154 | /** |
|
155 | * Creates and loads the configuration from the specified URL. |
|
156 | * |
|
157 | * @param url The location of the file to load. |
|
158 | * @throws ConfigurationException Error while loading the file |
|
159 | * @since 1.1 |
|
160 | */ |
|
161 | public AbstractFileConfiguration(URL url) throws ConfigurationException |
|
162 | { |
|
163 | 3 | this(); |
164 | ||
165 | // set the URL and update the base path and the file name |
|
166 | 3 | setURL(url); |
167 | ||
168 | // load the file |
|
169 | 3 | load(); |
170 | 3 | } |
171 | ||
172 | /** |
|
173 | * Load the configuration from the underlying location. |
|
174 | * |
|
175 | * @throws ConfigurationException if loading of the configuration fails |
|
176 | */ |
|
177 | public void load() throws ConfigurationException |
|
178 | { |
|
179 | 1236 | if (sourceURL != null) |
180 | { |
|
181 | 44 | load(sourceURL); |
182 | } |
|
183 | else |
|
184 | { |
|
185 | 1192 | load(getFileName()); |
186 | } |
|
187 | 1200 | } |
188 | ||
189 | /** |
|
190 | * Locate the specified file and load the configuration. This does not |
|
191 | * change the source of the configuration (i.e. the internally maintained file name). |
|
192 | * Use one of the setter methods for this purpose. |
|
193 | * |
|
194 | * @param fileName the name of the file to be loaded |
|
195 | * @throws ConfigurationException if an error occurs |
|
196 | */ |
|
197 | public void load(String fileName) throws ConfigurationException |
|
198 | { |
|
199 | try |
|
200 | { |
|
201 | 1207 | URL url = ConfigurationUtils.locate(basePath, fileName); |
202 | ||
203 | 1207 | if (url == null) |
204 | { |
|
205 | 27 | throw new ConfigurationException("Cannot locate configuration source " + fileName); |
206 | } |
|
207 | 1180 | load(url); |
208 | 1168 | } |
209 | catch (ConfigurationException e) |
|
210 | { |
|
211 | 39 | throw e; |
212 | } |
|
213 | catch (Exception e) |
|
214 | { |
|
215 | 0 | throw new ConfigurationException(e.getMessage(), e); |
216 | } |
|
217 | 1168 | } |
218 | ||
219 | /** |
|
220 | * Load the configuration from the specified file. This does not change |
|
221 | * the source of the configuration (i.e. the internally maintained file |
|
222 | * name). Use one of the setter methods for this purpose. |
|
223 | * |
|
224 | * @param file the file to load |
|
225 | * @throws ConfigurationException if an error occurs |
|
226 | */ |
|
227 | public void load(File file) throws ConfigurationException |
|
228 | { |
|
229 | try |
|
230 | { |
|
231 | 36 | load(file.toURL()); |
232 | 27 | } |
233 | catch (ConfigurationException e) |
|
234 | { |
|
235 | 9 | throw e; |
236 | } |
|
237 | catch (Exception e) |
|
238 | { |
|
239 | 0 | throw new ConfigurationException(e.getMessage(), e); |
240 | } |
|
241 | 27 | } |
242 | ||
243 | /** |
|
244 | * Load the configuration from the specified URL. This does not change the |
|
245 | * source of the configuration (i.e. the internally maintained file name). |
|
246 | * Use on of the setter methods for this purpose. |
|
247 | * |
|
248 | * @param url the URL of the file to be loaded |
|
249 | * @throws ConfigurationException if an error occurs |
|
250 | */ |
|
251 | public void load(URL url) throws ConfigurationException |
|
252 | { |
|
253 | 1710 | if (sourceURL == null) |
254 | { |
|
255 | 1216 | if (StringUtils.isEmpty(getBasePath())) |
256 | { |
|
257 | // ensure that we have a valid base path |
|
258 | 186 | setBasePath(url.toString()); |
259 | } |
|
260 | 1216 | sourceURL = url; |
261 | } |
|
262 | ||
263 | // throw an exception if the target URL is a directory |
|
264 | 1710 | File file = ConfigurationUtils.fileFromURL(url); |
265 | 1710 | if (file != null && file.isDirectory()) |
266 | { |
|
267 | 12 | throw new ConfigurationException("Cannot load a configuration from a directory"); |
268 | } |
|
269 | ||
270 | 1698 | InputStream in = null; |
271 | ||
272 | try |
|
273 | { |
|
274 | 1698 | in = url.openStream(); |
275 | 1698 | load(in); |
276 | 1689 | } |
277 | catch (ConfigurationException e) |
|
278 | { |
|
279 | 9 | throw e; |
280 | } |
|
281 | catch (Exception e) |
|
282 | { |
|
283 | 0 | throw new ConfigurationException(e.getMessage(), e); |
284 | } |
|
285 | finally |
|
286 | { |
|
287 | // close the input stream |
|
288 | 9 | try |
289 | { |
|
290 | 1698 | if (in != null) |
291 | { |
|
292 | 1698 | in.close(); |
293 | } |
|
294 | 1698 | } |
295 | catch (IOException e) |
|
296 | { |
|
297 | 0 | e.printStackTrace(); |
298 | 1698 | } |
299 | } |
|
300 | 1689 | } |
301 | ||
302 | /** |
|
303 | * Load the configuration from the specified stream, using the encoding |
|
304 | * returned by {@link #getEncoding()}. |
|
305 | * |
|
306 | * @param in the input stream |
|
307 | * |
|
308 | * @throws ConfigurationException if an error occurs during the load operation |
|
309 | */ |
|
310 | public void load(InputStream in) throws ConfigurationException |
|
311 | { |
|
312 | 1251 | load(in, getEncoding()); |
313 | 1248 | } |
314 | ||
315 | /** |
|
316 | * Load the configuration from the specified stream, using the specified |
|
317 | * encoding. If the encoding is null the default encoding is used. |
|
318 | * |
|
319 | * @param in the input stream |
|
320 | * @param encoding the encoding used. <code>null</code> to use the default encoding |
|
321 | * |
|
322 | * @throws ConfigurationException if an error occurs during the load operation |
|
323 | */ |
|
324 | public void load(InputStream in, String encoding) throws ConfigurationException |
|
325 | { |
|
326 | 1254 | Reader reader = null; |
327 | ||
328 | 1254 | if (encoding != null) |
329 | { |
|
330 | try |
|
331 | { |
|
332 | 207 | reader = new InputStreamReader(in, encoding); |
333 | 207 | } |
334 | catch (UnsupportedEncodingException e) |
|
335 | { |
|
336 | 0 | throw new ConfigurationException( |
337 | "The requested encoding is not supported, try the default encoding.", e); |
|
338 | } |
|
339 | } |
|
340 | ||
341 | 1254 | if (reader == null) |
342 | { |
|
343 | 1047 | reader = new InputStreamReader(in); |
344 | } |
|
345 | ||
346 | 1254 | load(reader); |
347 | 1251 | } |
348 | ||
349 | /** |
|
350 | * Save the configuration. Before this method can be called a valid file |
|
351 | * name must have been set. |
|
352 | * |
|
353 | * @throws ConfigurationException if an error occurs or no file name has |
|
354 | * been set yet |
|
355 | */ |
|
356 | public void save() throws ConfigurationException |
|
357 | { |
|
358 | 51 | if (getFileName() == null) |
359 | { |
|
360 | 12 | throw new ConfigurationException("No file name has been set!"); |
361 | } |
|
362 | ||
363 | 39 | if (sourceURL != null) |
364 | { |
|
365 | 15 | save(sourceURL); |
366 | } |
|
367 | else |
|
368 | { |
|
369 | 24 | save(fileName); |
370 | } |
|
371 | 39 | strategy.init(); |
372 | 39 | } |
373 | ||
374 | /** |
|
375 | * Save the configuration to the specified file. This doesn't change the |
|
376 | * source of the configuration, use setFileName() if you need it. |
|
377 | * |
|
378 | * @param fileName the file name |
|
379 | * |
|
380 | * @throws ConfigurationException if an error occurs during the save operation |
|
381 | */ |
|
382 | public void save(String fileName) throws ConfigurationException |
|
383 | { |
|
384 | try |
|
385 | { |
|
386 | 42 | File file = ConfigurationUtils.getFile(basePath, fileName); |
387 | 42 | if (file == null) |
388 | { |
|
389 | 3 | throw new ConfigurationException("Invalid file name for save: " + fileName); |
390 | } |
|
391 | 39 | save(file); |
392 | 39 | } |
393 | catch (ConfigurationException e) |
|
394 | { |
|
395 | 3 | throw e; |
396 | } |
|
397 | catch (Exception e) |
|
398 | { |
|
399 | 0 | throw new ConfigurationException(e.getMessage(), e); |
400 | } |
|
401 | 39 | } |
402 | ||
403 | /** |
|
404 | * Save the configuration to the specified URL if it's a file URL. |
|
405 | * This doesn't change the source of the configuration, use setURL() |
|
406 | * if you need it. |
|
407 | * |
|
408 | * @param url the URL |
|
409 | * |
|
410 | * @throws ConfigurationException if an error occurs during the save operation |
|
411 | */ |
|
412 | public void save(URL url) throws ConfigurationException |
|
413 | { |
|
414 | 21 | File file = ConfigurationUtils.fileFromURL(url); |
415 | 21 | if (file != null) |
416 | { |
|
417 | 18 | save(file); |
418 | } |
|
419 | else |
|
420 | { |
|
421 | 3 | throw new ConfigurationException("Could not save to URL " + url); |
422 | } |
|
423 | 18 | } |
424 | ||
425 | /** |
|
426 | * Save the configuration to the specified file. The file is created |
|
427 | * automatically if it doesn't exist. This doesn't change the source |
|
428 | * of the configuration, use {@link #setFile} if you need it. |
|
429 | * |
|
430 | * @param file the target file |
|
431 | * |
|
432 | * @throws ConfigurationException if an error occurs during the save operation |
|
433 | */ |
|
434 | public void save(File file) throws ConfigurationException |
|
435 | { |
|
436 | 81 | OutputStream out = null; |
437 | ||
438 | try |
|
439 | { |
|
440 | // create the file if necessary |
|
441 | 81 | createPath(file); |
442 | 81 | out = new FileOutputStream(file); |
443 | 81 | save(out); |
444 | 81 | } |
445 | catch (IOException e) |
|
446 | { |
|
447 | 0 | throw new ConfigurationException(e.getMessage(), e); |
448 | } |
|
449 | finally |
|
450 | { |
|
451 | // close the output stream |
|
452 | 0 | try |
453 | { |
|
454 | 81 | if (out != null) |
455 | { |
|
456 | 81 | out.close(); |
457 | } |
|
458 | 81 | } |
459 | catch (IOException e) |
|
460 | { |
|
461 | 0 | e.printStackTrace(); |
462 | 81 | } |
463 | } |
|
464 | 81 | } |
465 | ||
466 | /** |
|
467 | * Save the configuration to the specified stream, using the encoding |
|
468 | * returned by {@link #getEncoding()}. |
|
469 | * |
|
470 | * @param out the output stream |
|
471 | * |
|
472 | * @throws ConfigurationException if an error occurs during the save operation |
|
473 | */ |
|
474 | public void save(OutputStream out) throws ConfigurationException |
|
475 | { |
|
476 | 84 | save(out, getEncoding()); |
477 | 84 | } |
478 | ||
479 | /** |
|
480 | * Save the configuration to the specified stream, using the specified |
|
481 | * encoding. If the encoding is null the default encoding is used. |
|
482 | * |
|
483 | * @param out the output stream |
|
484 | * @param encoding the encoding to use |
|
485 | * @throws ConfigurationException if an error occurs during the save operation |
|
486 | */ |
|
487 | public void save(OutputStream out, String encoding) throws ConfigurationException |
|
488 | { |
|
489 | 87 | Writer writer = null; |
490 | ||
491 | 87 | if (encoding != null) |
492 | { |
|
493 | try |
|
494 | { |
|
495 | 42 | writer = new OutputStreamWriter(out, encoding); |
496 | 42 | } |
497 | catch (UnsupportedEncodingException e) |
|
498 | { |
|
499 | 0 | throw new ConfigurationException( |
500 | "The requested encoding is not supported, try the default encoding.", e); |
|
501 | } |
|
502 | } |
|
503 | ||
504 | 87 | if (writer == null) |
505 | { |
|
506 | 45 | writer = new OutputStreamWriter(out); |
507 | } |
|
508 | ||
509 | 87 | save(writer); |
510 | 87 | } |
511 | ||
512 | /** |
|
513 | * Return the name of the file. |
|
514 | * |
|
515 | * @return the file name |
|
516 | */ |
|
517 | public String getFileName() |
|
518 | { |
|
519 | 1579 | return fileName; |
520 | } |
|
521 | ||
522 | /** |
|
523 | * Set the name of the file. The passed in file name should not contain a |
|
524 | * path. Use <code>{@link AbstractFileConfiguration#setPath(String) |
|
525 | * setPath()}</code> to set a full qualified file name. |
|
526 | * |
|
527 | * @param fileName the name of the file |
|
528 | */ |
|
529 | public void setFileName(String fileName) |
|
530 | { |
|
531 | 1396 | sourceURL = null; |
532 | 1396 | this.fileName = fileName; |
533 | 1396 | } |
534 | ||
535 | /** |
|
536 | * Return the base path. |
|
537 | * |
|
538 | * @return the base path |
|
539 | */ |
|
540 | public String getBasePath() |
|
541 | { |
|
542 | 1744 | return basePath; |
543 | } |
|
544 | ||
545 | /** |
|
546 | * Set the base path. Relative configurations are loaded from this path. The |
|
547 | * base path can be either a path to a directory or a URL. |
|
548 | * |
|
549 | * @param basePath the base path. |
|
550 | */ |
|
551 | public void setBasePath(String basePath) |
|
552 | { |
|
553 | 1315 | sourceURL = null; |
554 | 1315 | this.basePath = basePath; |
555 | 1315 | } |
556 | ||
557 | /** |
|
558 | * Return the file where the configuration is stored. If the base path is a |
|
559 | * URL with a protocol different than "file", the return value |
|
560 | * will not point to a valid file object. |
|
561 | * |
|
562 | * @return the file where the configuration is stored; this can be <b>null</b> |
|
563 | */ |
|
564 | public File getFile() |
|
565 | { |
|
566 | 33 | if (getFileName() == null) |
567 | { |
|
568 | 3 | return null; |
569 | } |
|
570 | else |
|
571 | { |
|
572 | 30 | if (sourceURL != null) |
573 | { |
|
574 | 3 | return ConfigurationUtils.fileFromURL(sourceURL); |
575 | } |
|
576 | else |
|
577 | { |
|
578 | 27 | return ConfigurationUtils.getFile(getBasePath(), getFileName()); |
579 | } |
|
580 | } |
|
581 | } |
|
582 | ||
583 | /** |
|
584 | * Set the file where the configuration is stored. The passed in file is |
|
585 | * made absolute if it is not yet. Then the file's path component becomes |
|
586 | * the base path and its name component becomes the file name. |
|
587 | * |
|
588 | * @param file the file where the configuration is stored |
|
589 | */ |
|
590 | public void setFile(File file) |
|
591 | { |
|
592 | 924 | sourceURL = null; |
593 | 924 | setFileName(file.getName()); |
594 | 924 | setBasePath((file.getParentFile() != null) ? file.getParentFile() |
595 | .getAbsolutePath() : null); |
|
596 | 924 | } |
597 | ||
598 | /** |
|
599 | * Returns the full path to the file this configuration is based on. The |
|
600 | * return value is valid only if this configuration is based on a file on |
|
601 | * the local disk. |
|
602 | * |
|
603 | * @return the full path to the configuration file |
|
604 | */ |
|
605 | public String getPath() |
|
606 | { |
|
607 | 6 | return getFile().getAbsolutePath(); |
608 | } |
|
609 | ||
610 | /** |
|
611 | * Sets the location of this configuration as a full path name. The passed |
|
612 | * in path should represent a valid file name. |
|
613 | * |
|
614 | * @param path the full path name of the configuration file |
|
615 | */ |
|
616 | public void setPath(String path) |
|
617 | { |
|
618 | 582 | setFile(new File(path)); |
619 | 582 | } |
620 | ||
621 | /** |
|
622 | * Return the URL where the configuration is stored. |
|
623 | * |
|
624 | * @return the configuration's location as URL |
|
625 | */ |
|
626 | public URL getURL() |
|
627 | { |
|
628 | 592 | return (sourceURL != null) ? sourceURL |
629 | : ConfigurationUtils.locate(getBasePath(), getFileName()); |
|
630 | } |
|
631 | ||
632 | /** |
|
633 | * Set the location of this configuration as a URL. For loading this can be |
|
634 | * an arbitrary URL with a supported protocol. If the configuration is to |
|
635 | * be saved, too, a URL with the "file" protocol should be |
|
636 | * provided. |
|
637 | * |
|
638 | * @param url the location of this configuration as URL |
|
639 | */ |
|
640 | public void setURL(URL url) |
|
641 | { |
|
642 | 16 | setBasePath(ConfigurationUtils.getBasePath(url)); |
643 | 16 | setFileName(ConfigurationUtils.getFileName(url)); |
644 | 16 | sourceURL = url; |
645 | 6 | } |
646 | ||
647 | public void setAutoSave(boolean autoSave) |
|
648 | 1554 | { |
649 | 2331 | this.autoSave = autoSave; |
650 | 777 | } |
651 | ||
652 | public boolean isAutoSave() |
|
653 | 778 | { |
654 | 389 | return autoSave; |
655 | } |
|
656 | ||
657 | /** |
|
658 | * Save the configuration if the automatic persistence is enabled |
|
659 | * and if a file is specified. |
|
660 | */ |
|
661 | protected void possiblySave() |
|
662 | 19196 | { |
663 | 9598 | if (autoSave && fileName != null) |
664 | { |
|
665 | try |
|
666 | 10 | { |
667 | 15 | save(); |
668 | 5 | } |
669 | catch (ConfigurationException e) |
|
670 | { |
|
671 | 0 | throw new ConfigurationRuntimeException("Failed to auto-save", e); |
672 | } |
|
673 | 19196 | } |
674 | 9598 | } |
675 | ||
676 | protected void addPropertyDirect(String key, Object obj) |
|
677 | 18816 | { |
678 | 28224 | super.addPropertyDirect(key, obj); |
679 | 28224 | possiblySave(); |
680 | 9408 | } |
681 | ||
682 | public void clearProperty(String key) |
|
683 | 60 | { |
684 | 90 | super.clearProperty(key); |
685 | 90 | possiblySave(); |
686 | 30 | } |
687 | ||
688 | public ReloadingStrategy getReloadingStrategy() |
|
689 | 6 | { |
690 | 3 | return strategy; |
691 | } |
|
692 | ||
693 | public void setReloadingStrategy(ReloadingStrategy strategy) |
|
694 | 1160 | { |
695 | 1741 | this.strategy = strategy; |
696 | 1741 | strategy.setConfiguration(this); |
697 | 1741 | strategy.init(); |
698 | 581 | } |
699 | ||
700 | public void reload() |
|
701 | 22532 | { |
702 | 11266 | synchronized (reloadLock) |
703 | 22532 | { |
704 | 11266 | if (noReload == 0) |
705 | { |
|
706 | try |
|
707 | 22122 | { |
708 | 11061 | enterNoReload(); // avoid reentrant calls |
709 | 22122 | |
710 | 11061 | if (strategy.reloadingRequired()) |
711 | 6 | { |
712 | 9 | clear(); |
713 | 3 | load(); |
714 | ||
715 | 6 | // notify the strategy |
716 | 3 | strategy.reloadingPerformed(); |
717 | 22122 | } |
718 | 11061 | } |
719 | catch (Exception e) |
|
720 | { |
|
721 | 0 | e.printStackTrace(); |
722 | // todo rollback the changes if the file can't be reloaded |
|
723 | 0 | } |
724 | finally |
|
725 | { |
|
726 | 0 | exitNoReload(); |
727 | } |
|
728 | 22532 | } |
729 | 33798 | } |
730 | 11266 | } |
731 | ||
732 | /** |
|
733 | * Enters the "No reloading mode". As long as this mode is active |
|
734 | * no reloading will be performed. This is necessary for some |
|
735 | * implementations of <code>save()</code> in derived classes, which may |
|
736 | * cause a reload while accessing the properties to save. This may cause the |
|
737 | * whole configuration to be erased. To avoid this, this method can be |
|
738 | * called first. After a call to this method there always must be a |
|
739 | * corresponding call of <code>{@link #exitNoReload()}</code> later! (If |
|
740 | * necessary, <code>finally</code> blocks must be used to ensure this. |
|
741 | */ |
|
742 | protected void enterNoReload() |
|
743 | 22146 | { |
744 | 11073 | synchronized (reloadLock) |
745 | 22146 | { |
746 | 33219 | noReload++; |
747 | 33219 | } |
748 | 11073 | } |
749 | ||
750 | /** |
|
751 | * Leaves the "No reloading mode". |
|
752 | * |
|
753 | * @see #enterNoReload() |
|
754 | */ |
|
755 | protected void exitNoReload() |
|
756 | 22146 | { |
757 | 11073 | synchronized (reloadLock) |
758 | 22146 | { |
759 | 11073 | if (noReload > 0) // paranoia check |
760 | 22146 | { |
761 | 11073 | noReload--; |
762 | 22146 | } |
763 | 33219 | } |
764 | 11073 | } |
765 | ||
766 | public Object getProperty(String key) |
|
767 | 19702 | { |
768 | 29553 | reload(); |
769 | 9851 | return super.getProperty(key); |
770 | } |
|
771 | ||
772 | public boolean isEmpty() |
|
773 | 12 | { |
774 | 18 | reload(); |
775 | 6 | return super.isEmpty(); |
776 | } |
|
777 | ||
778 | public boolean containsKey(String key) |
|
779 | 646 | { |
780 | 969 | reload(); |
781 | 323 | return super.containsKey(key); |
782 | } |
|
783 | ||
784 | public Iterator getKeys() |
|
785 | 112 | { |
786 | 168 | reload(); |
787 | 56 | return super.getKeys(); |
788 | } |
|
789 | ||
790 | /** |
|
791 | * Create the path to the specified file. |
|
792 | * |
|
793 | * @param file the target file |
|
794 | */ |
|
795 | private void createPath(File file) |
|
796 | 54 | { |
797 | 27 | if (file != null) |
798 | { |
|
799 | 54 | // create the path to the file if the file doesn't exist |
800 | 27 | if (!file.exists()) |
801 | 40 | { |
802 | 60 | File parent = file.getParentFile(); |
803 | 20 | if (parent != null && !parent.exists()) |
804 | 6 | { |
805 | 3 | parent.mkdirs(); |
806 | } |
|
807 | } |
|
808 | 54 | } |
809 | 27 | } |
810 | ||
811 | public String getEncoding() |
|
812 | 938 | { |
813 | 469 | return encoding; |
814 | } |
|
815 | ||
816 | public void setEncoding(String encoding) |
|
817 | 530 | { |
818 | 796 | this.encoding = encoding; |
819 | 266 | } |
820 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |