Coverage report

  %line %branch
org.apache.commons.configuration.AbstractFileConfiguration
80% 
99% 

 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  
 
 35  
 /**
 36  
  * <p>Partial implementation of the <code>FileConfiguration</code> interface.
 37  
  * Developpers of file based configuration may want to extend this class,
 38  
  * the two methods left to implement are {@see AbstractFileConfiguration#load(Reader)}
 39  
  * and {@see AbstractFileConfiguration#save(Reader)}.</p>
 40  
  * <p>This base class already implements a couple of ways to specify the location
 41  
  * of the file this configuration is based on. The following possibilities
 42  
  * exist:
 43  
  * <ul><li>URLs: With the method <code>setURL()</code> a full URL to the
 44  
  * configuration source can be specified. This is the most flexible way. Note
 45  
  * that the <code>save()</code> methods support only <em>file:</em> URLs.</li>
 46  
  * <li>Files: The <code>setFile()</code> method allows to specify the
 47  
  * configuration source as a file. This can be either a relative or an
 48  
  * absolute file. In the former case the file is resolved based on the current
 49  
  * directory.</li>
 50  
  * <li>As file paths in string form: With the <code>setPath()</code> method a
 51  
  * full path to a configuration file can be provided as a string.</li>
 52  
  * <li>Separated as base path and file name: This is the native form in which
 53  
  * the location is stored. The base path is a string defining either a local
 54  
  * directory or a URL. It can be set using the <code>setBasePath()</code>
 55  
  * method. The file name, non surprisingly, defines the name of the configuration
 56  
  * file.</li></ul></p>
 57  
  * <p>Note that the <code>load()</code> methods do not wipe out the configuration's
 58  
  * content before the new configuration file is loaded. Thus it is very easy to
 59  
  * construct a union configuration by simply loading multiple configuration
 60  
  * files, e.g.</p>
 61  
  * <p><pre>
 62  
  * config.load(configFile1);
 63  
  * config.load(configFile2);
 64  
  * </pre></p>
 65  
  * <p>After executing this code fragment, the resulting configuration will
 66  
  * contain both the properties of configFile1 and configFile2. On the other
 67  
  * hand, if the current configuration file is to be reloaded, <code>clear()</code>
 68  
  * should be called first. Otherwise the properties are doubled. This behavior
 69  
  * is analogous to the behavior of the <code>load(InputStream)</code> method
 70  
  * in <code>java.util.Properties</code>.</p>
 71  
  *
 72  3033
  * @author Emmanuel Bourg
 73  
  * @version $Revision: 156237 $, $Date: 2005-03-05 11:26:22 +0100 (Sa, 05 Mrz 2005) $
 74  
  * @since 1.0-rc2
 75  
  */
 76  
 public abstract class AbstractFileConfiguration extends BaseConfiguration implements FileConfiguration
 77  
 {
 78  
     protected String fileName;
 79  
 
 80  
     protected String basePath;
 81  
 
 82  3033
     protected boolean autoSave;
 83  3033
 
 84  3033
     protected ReloadingStrategy strategy;
 85  
 
 86  4802
     private Object reloadLock = new Object();
 87  
 
 88  
     private String encoding;
 89  
 
 90  
     /**
 91  
      * Default constructor
 92  
      *
 93  
      * @since 1.1
 94  
      */
 95  
     public AbstractFileConfiguration()
 96  4802
     {
 97  6431
         setReloadingStrategy(new InvariantReloadingStrategy());
 98  4802
     }
 99  
 
 100  1629
     /**
 101  
      * Creates and loads the configuration from the specified file. The passed
 102  
      * in string must be a valid file name, either absolute or relativ.
 103  1629
      *
 104  1620
      * @param fileName The name of the file to load.
 105  
      *
 106  
      * @throws ConfigurationException Error while loading the file
 107  
      * @since 1.1
 108  
      */
 109  
     public AbstractFileConfiguration(String fileName) throws ConfigurationException
 110  
     {
 111  2548
         this();
 112  
 
 113  
         // store the file name
 114  2548
         setPath(fileName);
 115  18
 
 116  
         // load the file
 117  2548
         load();
 118  2552
     }
 119  
 
 120  
     /**
 121  18
      * Creates and loads the configuration from the specified file.
 122  
      *
 123  9
      * @param file The file to load.
 124  
      * @throws ConfigurationException Error while loading the file
 125  18
      * @since 1.1
 126  
      */
 127  
     public AbstractFileConfiguration(File file) throws ConfigurationException
 128  
     {
 129  28
         this();
 130  
 
 131  
         // set the file and update the url, the base path and the file name
 132  28
         setFile(file);
 133  
 
 134  
         // load the file
 135  28
         if (file.exists())
 136  
         {
 137  14
             load();
 138  
         }
 139  28
     }
 140  
 
 141  
     /**
 142  
      * Creates and loads the configuration from the specified URL.
 143  
      *
 144  
      * @param url The location of the file to load.
 145  
      * @throws ConfigurationException Error while loading the file
 146  
      * @since 1.1
 147  
      */
 148  
     public AbstractFileConfiguration(URL url) throws ConfigurationException
 149  
     {
 150  0
         this();
 151  
 
 152  2961
         // set the URL and update the base path and the file name
 153  2880
         setURL(url);
 154  
 
 155  
         // load the file
 156  0
         load();
 157  0
     }
 158  
 
 159  
     /**
 160  
      * Load the configuration from the underlying location.
 161  
      *
 162  
      * @throws ConfigurationException if loading of the configuration fails
 163  
      */
 164  
     public void load() throws ConfigurationException
 165  
     {
 166  7655
         load(getFileName());
 167  7529
     }
 168  
 
 169  81
     /**
 170  
      * Locate the specified file and load the configuration.
 171  2898
      *
 172  
      * @param fileName the name of the file loaded
 173  81
      *
 174  
      * @throws ConfigurationException
 175  81
      */
 176  
     public void load(String fileName) throws ConfigurationException
 177  
     {
 178  
         try
 179  
         {
 180  7616
             URL url = ConfigurationUtils.locate(basePath, fileName);
 181  7616
             if (url == null)
 182  
             {
 183  126
                 throw new ConfigurationException("Cannot locate configuration source " + fileName);
 184  
             }
 185  4592
             load(url);
 186  
         }
 187  126
         catch (ConfigurationException e)
 188  
         {
 189  126
             throw e;
 190  
         }
 191  0
         catch (Exception e)
 192  
         {
 193  0
             throw new ConfigurationException(e.getMessage(), e);
 194  4601
         }
 195  4592
     }
 196  
 
 197  
     /**
 198  
      * Load the configuration from the specified file.
 199  
      *
 200  
      * @param file the loaded file
 201  
      *
 202  
      * @throws ConfigurationException
 203  9
      */
 204  9
     public void load(File file) throws ConfigurationException
 205  
     {
 206  
         try
 207  
         {
 208  28
             load(file.toURL());
 209  
         }
 210  0
         catch (ConfigurationException e)
 211  
         {
 212  0
             throw e;
 213  
         }
 214  0
         catch (Exception e)
 215  4086
         {
 216  0
             throw new ConfigurationException(e.getMessage(), e);
 217  28
         }
 218  28
     }
 219  4086
 
 220  4086
     /**
 221  4086
      * Load the configuration from the specified URL.
 222  
      *
 223  
      * @param url the URL of the file loaded
 224  
      *
 225  
      * @throws ConfigurationException
 226  
      */
 227  
     public void load(URL url) throws ConfigurationException
 228  
     {
 229  6482
         InputStream in = null;
 230  
 
 231  
         try
 232  
         {
 233  6482
             in = url.openStream();
 234  6482
             load(in);
 235  10568
         }
 236  0
         catch (ConfigurationException e)
 237  4086
         {
 238  0
             throw e;
 239  
         }
 240  0
         catch (Exception e)
 241  
         {
 242  0
             throw new ConfigurationException(e.getMessage(), e);
 243  8172
         }
 244  4086
         finally
 245  4086
         {
 246  
             // close the input stream
 247  0
             try
 248  
             {
 249  6482
                 if (in != null)
 250  
                 {
 251  6482
                     in.close();
 252  
                 }
 253  
             }
 254  0
             catch (IOException e)
 255  
             {
 256  0
                 e.printStackTrace();
 257  17050
             }
 258  10568
         }
 259  6482
     }
 260  
 
 261  
     /**
 262  
      * Load the configuration from the specified stream, using the encoding
 263  
      * returned by {@link #getEncoding()}.
 264  
      *
 265  
      * @param in the input stream
 266  
      *
 267  
      * @throws ConfigurationException
 268  
      */
 269  
     public void load(InputStream in) throws ConfigurationException
 270  
     {
 271  10568
         load(in, getEncoding());
 272  6482
     }
 273  4086
 
 274  
     /**
 275  
      * Load the configuration from the specified stream, using the specified
 276  
      * encoding. If the encoding is null the default encoding is used.
 277  
      *
 278  
      * @param in the input stream
 279  
      * @param encoding the encoding used. <code>null</code> to use the default encoding
 280  
      *
 281  
      * @throws ConfigurationException
 282  
      */
 283  
     public void load(InputStream in, String encoding) throws ConfigurationException
 284  
     {
 285  6482
         Reader reader = null;
 286  4086
 
 287  6482
         if (encoding != null)
 288  4086
         {
 289  
             try
 290  
             {
 291  4086
                 reader = new InputStreamReader(in, encoding);
 292  4086
             }
 293  0
             catch (UnsupportedEncodingException e)
 294  
             {
 295  0
                 throw new ConfigurationException(
 296  
                         "The requested encoding is not supported, try the default encoding.", e);
 297  0
             }
 298  
         }
 299  
 
 300  6482
         if (reader == null)
 301  81
         {
 302  6554
             reader = new InputStreamReader(in);
 303  72
         }
 304  
 
 305  6482
         load(reader);
 306  6482
     }
 307  
 
 308  
     /**
 309  
      * Save the configuration.
 310  
      *
 311  
      * @throws ConfigurationException
 312  
      */
 313  
     public void save() throws ConfigurationException
 314  
     {
 315  126
         save(fileName);
 316  112
         strategy.init();
 317  238
     }
 318  117
 
 319  
     /**
 320  9
      * Save the configuration to the specified file. This doesn't change the
 321  
      * source of the configuration, use setFileName() if you need it.
 322  108
      *
 323  
      * @param fileName
 324  9
      *
 325  
      * @throws ConfigurationException
 326  9
      */
 327  
     public void save(String fileName) throws ConfigurationException
 328  9
     {
 329  
         try
 330  9
         {
 331  304
             File file = ConfigurationUtils.getFile(basePath, fileName);
 332  290
             if (file == null)
 333  
             {
 334  14
                 throw new ConfigurationException("Invalid file name for save: " + fileName);
 335  
             }
 336  168
             save(file);
 337  
         }
 338  14
         catch (ConfigurationException e)
 339  
         {
 340  14
             throw e;
 341  
         }
 342  14
         catch (Exception e)
 343  
         {
 344  14
             throw new ConfigurationException(e.getMessage(), e);
 345  177
         }
 346  177
     }
 347  
 
 348  
     /**
 349  
      * Save the configuration to the specified URL if it's a file URL.
 350  
      * This doesn't change the source of the configuration, use setURL()
 351  
      * if you need it.
 352  9
      *
 353  
      * @param url
 354  
      *
 355  
      * @throws ConfigurationException
 356  
      */
 357  
     public void save(URL url) throws ConfigurationException
 358  
     {
 359  14
         File file = ConfigurationUtils.fileFromURL(url);
 360  14
         if (file != null)
 361  
         {
 362  0
             save(file);
 363  
         }
 364  
         else
 365  
         {
 366  14
             throw new ConfigurationException("Could not save to URL " + url);
 367  135
         }
 368  0
     }
 369  
 
 370  
     /**
 371  
      * Save the configuration to the specified file. The file is created
 372  135
      * automatically if it doesn't exist. This doesn't change the source
 373  135
      * of the configuration, use {@link #setFile} if you need it.
 374  135
      *
 375  135
      * @param file
 376  
      *
 377  
      * @throws ConfigurationException
 378  
      */
 379  
     public void save(File file) throws ConfigurationException
 380  
     {
 381  224
         OutputStream out = null;
 382  
 
 383  
         try
 384  
         {
 385  135
             // create the file if necessary
 386  224
             createPath(file);
 387  359
             out = new FileOutputStream(file);
 388  224
             save(out);
 389  224
         }
 390  0
         catch (IOException e)
 391  
         {
 392  0
             throw new ConfigurationException(e.getMessage(), e);
 393  270
         }
 394  135
         finally
 395  135
         {
 396  
             // close the output stream
 397  0
             try
 398  
             {
 399  224
                 if (out != null)
 400  
                 {
 401  224
                     out.close();
 402  
                 }
 403  
             }
 404  0
             catch (IOException e)
 405  
             {
 406  0
                 e.printStackTrace();
 407  583
             }
 408  359
         }
 409  224
     }
 410  
 
 411  
     /**
 412  
      * Save the configuration to the specified stream, using the encoding
 413  
      * returned by {@link #getEncoding()}.
 414  
      *
 415  
      * @param out
 416  
      *
 417  
      * @throws ConfigurationException
 418  
      */
 419  
     public void save(OutputStream out) throws ConfigurationException
 420  135
     {
 421  224
         save(out, getEncoding());
 422  359
     }
 423  
 
 424  
     /**
 425  
      * Save the configuration to the specified stream, using the specified
 426  9
      * encoding. If the encoding is null the default encoding is used.
 427  
      *
 428  
      * @param out
 429  
      * @param encoding
 430  
      * @throws ConfigurationException
 431  
      */
 432  9
     public void save(OutputStream out, String encoding) throws ConfigurationException
 433  
     {
 434  224
         Writer writer = null;
 435  135
 
 436  224
         if (encoding != null)
 437  126
         {
 438  
             try
 439  
             {
 440  149
                 writer = new OutputStreamWriter(out, encoding);
 441  135
             }
 442  0
             catch (UnsupportedEncodingException e)
 443  
             {
 444  0
                 throw new ConfigurationException(
 445  
                         "The requested encoding is not supported, try the default encoding.", e);
 446  14
             }
 447  
         }
 448  3735
 
 449  224
         if (writer == null)
 450  
         {
 451  210
             writer = new OutputStreamWriter(out);
 452  
         }
 453  
 
 454  224
         save(writer);
 455  224
     }
 456  
 
 457  
     /**
 458  
      * Return the name of the file.
 459  
      */
 460  3420
     public String getFileName()
 461  3420
     {
 462  5950
         return fileName;
 463  
     }
 464  
 
 465  
     /**
 466  
      * Set the name of the file. The passed in file name should not contain a
 467  
      * path. Use <code>{@link AbstractFileConfiguration#setPath(String)
 468  1314
      * setPath()}</code> to set a full qualified file name.
 469  
      *
 470  
      * @param fileName the name of the file
 471  
      */
 472  
     public void setFileName(String fileName)
 473  
     {
 474  5418
         this.fileName = fileName;
 475  5418
     }
 476  
 
 477  
     /**
 478  
      * Return the base path.
 479  2889
      */
 480  2889
     public String getBasePath()
 481  
     {
 482  2170
         return basePath;
 483  
     }
 484  
 
 485  
     /**
 486  
      * Set the base path. Relative configurations are loaded from this path.
 487  
      * The base path can be either a path to a directory or a URL.
 488  
      *
 489  
      * @param basePath the base path.
 490  
      */
 491  90
     public void setBasePath(String basePath)
 492  
     {
 493  4564
         this.basePath = basePath;
 494  4564
     }
 495  
 
 496  
     /**
 497  
      * Return the file where the configuration is stored. If the base path is
 498  
      * a URL with a protocol different than &quot;file&quot;, the return value
 499  
      * will not point to a valid file object.
 500  
      * 
 501  
      * @return the file where the configuration is stored
 502  
      */
 503  2340
     public File getFile()
 504  2340
     {
 505  2578
         return ConfigurationUtils.getFile(getBasePath(), getFileName());
 506  
     }
 507  
 
 508  
     /**
 509  
      * Set the file where the configuration is stored. The passed in file is
 510  
      * made absolute if it is not yet. Then the file's path component becomes
 511  
      * the base path and its name component becomes the file name.
 512  
      *
 513  
      * @param file the file where the configuration is stored
 514  
      */
 515  
     public void setFile(File file)
 516  18
     {
 517  3696
         setFileName(file.getName());
 518  3696
         setBasePath((file.getParentFile() != null) ? file.getParentFile().getAbsolutePath() : class="keyword">null);
 519  3696
     }
 520  
 
 521  
     /**
 522  
      * Returns the full path to the file this configuration is based on. The
 523  
      * return value is valid only if this configuration is based on a file on
 524  
      * the local disk.
 525  
      * 
 526  
      * @return the full path to the configuration file
 527  1638
      */
 528  1638
     public String getPath()
 529  
     {
 530  28
         return getFile().getAbsolutePath();
 531  
     }
 532  
 
 533  
     /**
 534  
      * Sets the location of this configuration as a full path name. The passed
 535  
      * in path should represent a valid file name.
 536  
      * 
 537  9
      * @param path the full path name of the configuration file
 538  
      */
 539  
     public void setPath(String path)
 540  
     {
 541  2562
         setFile(new File(path));
 542  2562
     }
 543  
 
 544  
     /**
 545  
      * Return the URL where the configuration is stored.
 546  
      * 
 547  
      * @return the configuration's location as URL
 548  
      */
 549  
     public URL getURL()
 550  18
     {
 551  32
         return ConfigurationUtils.locate(getBasePath(), getFileName());
 552  18
     }
 553  
 
 554  
     /**
 555  
      * Set the location of this configuration as a URL. For loading this can be
 556  9
      * an arbitrary URL with a supported protocol. If the configuration is to
 557  9
      * be saved, too, a URL with the &quot;file&quot; protocol should be
 558  
      * provided.
 559  
      *
 560  
      * @param url the location of this configuration as URL
 561  
      */
 562  
     public void setURL(URL url)
 563  
     {
 564  28
         setBasePath(ConfigurationUtils.getBasePath(url));
 565  28
         setFileName(ConfigurationUtils.getFileName(url));
 566  28
     }
 567  
 
 568  
     public void setAutoSave(boolean autoSave)
 569  
     {
 570  62348
         this.autoSave = autoSave;
 571  14
     }
 572  
 
 573  
     public boolean isAutoSave()
 574  27
     {
 575  0
         return autoSave;
 576  
     }
 577  
 
 578  
     /**
 579  27
      * Save the configuration if the automatic persistence is enabled
 580  
      * and if a file is specified.
 581  62334
      */
 582  
     protected void possiblySave()
 583  
     {
 584  98238
         if (autoSave && fileName != null)
 585  61542
         {
 586  61542
             try
 587  61542
             {
 588  42
                 save();
 589  
             }
 590  0
             catch (ConfigurationException e)
 591  225
             {
 592  225
                 throw new ConfigurationRuntimeException("Failed to auto-save", e);
 593  267
             }
 594  
         }
 595  98238
     }
 596  
 
 597  
     protected void addPropertyDirect(String key, Object obj)
 598  
     {
 599  97006
         super.addPropertyDirect(key, obj);
 600  97006
         possiblySave();
 601  97006
     }
 602  3042
 
 603  3042
     public void clearProperty(String key)
 604  3042
     {
 605  3392
         super.clearProperty(key);
 606  350
         possiblySave();
 607  350
     }
 608  
 
 609  67914
     public ReloadingStrategy getReloadingStrategy()
 610  
     {
 611  67914
         return strategy;
 612  
     }
 613  
 
 614  
     public void setReloadingStrategy(ReloadingStrategy strategy)
 615  18
     {
 616  4848
         this.strategy = strategy;
 617  4830
         strategy.setConfiguration(this);
 618  4830
         strategy.init();
 619  4848
     }
 620  
 
 621  
     public void reload()
 622  
     {
 623  107002
         synchronized (reloadLock)
 624  
         {
 625  107020
             if (strategy.reloadingRequired())
 626  
             {
 627  67914
                 try
 628  67914
                 {
 629  28
                     clear();
 630  28
                     load();
 631  
 
 632  64710
                     // notify the strategy
 633  64738
                     strategy.reloadingPerformed();
 634  
                 }
 635  0
                 catch (Exception e)
 636  
                 {
 637  0
                     e.printStackTrace();
 638  63
                     // todo rollback the changes if the file can't be reloaded
 639  91
                 }
 640  
             }
 641  107002
         }
 642  107002
     }
 643  
 
 644  2682
     public Object getProperty(String key)
 645  2682
     {
 646  102004
         reload();
 647  102004
         return super.getProperty(key);
 648  
     }
 649  
 
 650  459
     public boolean isEmpty()
 651  459
     {
 652  98
         reload();
 653  98
         return super.isEmpty();
 654  
     }
 655  
 
 656  
     public boolean containsKey(String key)
 657  
     {
 658  4186
         reload();
 659  4321
         return super.containsKey(key);
 660  
     }
 661  
 
 662  135
     public Iterator getKeys()
 663  
     {
 664  804
         reload();
 665  804
         return super.getKeys();
 666  
     }
 667  27
 
 668  
     /**
 669  
      * Create the path to the specified file.
 670  
      */
 671  135
     private void createPath(File file)
 672  
     {
 673  224
         if (file != null)
 674  
         {
 675  4239
             // create the path to the file if the file doesn't exist
 676  224
             if (!file.exists())
 677  
             {
 678  154
                 File parent = file.getParentFile();
 679  154
                 if (parent != null && !parent.exists())
 680  27
                 {
 681  69
                     parent.mkdirs();
 682  
                 }
 683  
             }
 684  
         }
 685  224
     }
 686  
 
 687  
     public String getEncoding()
 688  
     {
 689  6734
         return encoding;
 690  
     }
 691  
 
 692  
     public void setEncoding(String encoding)
 693  
     {
 694  42
         this.encoding = encoding;
 695  42
     }
 696  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.