| %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. |