Coverage Report - org.apache.commons.configuration.AbstractHierarchicalFileConfiguration
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractHierarchicalFileConfiguration
92%
138/150
75%
3/4
1,067
AbstractHierarchicalFileConfiguration$FileConfigurationDelegate
100%
7/7
N/A
1,067
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.commons.configuration;
 19  
 
 20  
 import java.io.File;
 21  
 import java.io.InputStream;
 22  
 import java.io.OutputStream;
 23  
 import java.io.Reader;
 24  
 import java.io.Writer;
 25  
 import java.net.URL;
 26  
 import java.util.Collection;
 27  
 import java.util.Iterator;
 28  
 import java.util.List;
 29  
 
 30  
 import org.apache.commons.configuration.event.ConfigurationErrorEvent;
 31  
 import org.apache.commons.configuration.event.ConfigurationErrorListener;
 32  
 import org.apache.commons.configuration.event.ConfigurationEvent;
 33  
 import org.apache.commons.configuration.event.ConfigurationListener;
 34  
 import org.apache.commons.configuration.reloading.Reloadable;
 35  
 import org.apache.commons.configuration.reloading.ReloadingStrategy;
 36  
 import org.apache.commons.configuration.tree.ConfigurationNode;
 37  
 
 38  
 /**
 39  
  * <p>Base class for implementing file based hierarchical configurations.</p>
 40  
  * <p>This class serves an analogous purpose as the
 41  
  * {@link AbstractFileConfiguration} class for non hierarchical
 42  
  * configurations. It behaves in exactly the same way, so please refer to the
 43  
  * documentation of {@code AbstractFileConfiguration} for further details.</p>
 44  
  *
 45  
  * @since 1.2
 46  
  *
 47  
  * @author Emmanuel Bourg
 48  
  * @version $Id: org.apache.commons.configuration.AbstractHierarchicalFileConfiguration.html 901807 2014-03-16 10:49:30Z oheger $
 49  
  */
 50  
 public abstract class AbstractHierarchicalFileConfiguration
 51  
 extends HierarchicalConfiguration
 52  
 implements FileConfiguration, ConfigurationListener, ConfigurationErrorListener, FileSystemBased,
 53  
         Reloadable
 54  
 {
 55  
     /** Stores the delegate used for implementing functionality related to the
 56  
      * {@code FileConfiguration} interface.
 57  
      */
 58  
     private FileConfigurationDelegate delegate;
 59  
 
 60  
     /**
 61  
      * Creates a new instance of {@code AbstractHierarchicalFileConfiguration}.
 62  
      */
 63  
     protected AbstractHierarchicalFileConfiguration()
 64  1153
     {
 65  1153
         initialize();
 66  1153
     }
 67  
 
 68  
     /**
 69  
      * Creates a new instance of
 70  
      * {@code AbstractHierarchicalFileConfiguration} and copies the
 71  
      * content of the specified configuration into this object.
 72  
      *
 73  
      * @param c the configuration to copy
 74  
      * @since 1.4
 75  
      */
 76  
     protected AbstractHierarchicalFileConfiguration(HierarchicalConfiguration c)
 77  
     {
 78  13
         super(c);
 79  13
         initialize();
 80  13
     }
 81  
 
 82  
     /**
 83  
      * Creates and loads the configuration from the specified file.
 84  
      *
 85  
      * @param fileName The name of the plist file to load.
 86  
      * @throws ConfigurationException Error while loading the file
 87  
      */
 88  
     public AbstractHierarchicalFileConfiguration(String fileName) throws ConfigurationException
 89  
     {
 90  14
         this();
 91  
         // store the file name
 92  14
         delegate.setFileName(fileName);
 93  
 
 94  
         // load the file
 95  14
         load();
 96  14
     }
 97  
 
 98  
     /**
 99  
      * Creates and loads the configuration from the specified file.
 100  
      *
 101  
      * @param file The configuration file to load.
 102  
      * @throws ConfigurationException Error while loading the file
 103  
      */
 104  
     public AbstractHierarchicalFileConfiguration(File file) throws ConfigurationException
 105  
     {
 106  168
         this();
 107  
         // set the file and update the url, the base path and the file name
 108  168
         setFile(file);
 109  
 
 110  
         // load the file
 111  168
         if (file.exists())
 112  
         {
 113  147
             load();
 114  
         }
 115  168
     }
 116  
 
 117  
     /**
 118  
      * Creates and loads the configuration from the specified URL.
 119  
      *
 120  
      * @param url The location of the configuration file to load.
 121  
      * @throws ConfigurationException Error while loading the file
 122  
      */
 123  
     public AbstractHierarchicalFileConfiguration(URL url) throws ConfigurationException
 124  
     {
 125  2
         this();
 126  
         // set the URL and update the base path and the file name
 127  2
         setURL(url);
 128  
 
 129  
         // load the file
 130  2
         load();
 131  2
     }
 132  
 
 133  
     /**
 134  
      * Initializes this instance, mainly the internally used delegate object.
 135  
      */
 136  
     private void initialize()
 137  
     {
 138  1166
         delegate = createDelegate();
 139  1166
         initDelegate(delegate);
 140  1166
     }
 141  
 
 142  
     @Override
 143  
     protected void addPropertyDirect(String key, Object obj)
 144  
     {
 145  3536
         synchronized (delegate.getReloadLock())
 146  
         {
 147  3536
             super.addPropertyDirect(key, obj);
 148  3536
             delegate.possiblySave();
 149  3536
         }
 150  3536
     }
 151  
 
 152  
     @Override
 153  
     public void clearProperty(String key)
 154  
     {
 155  33
         synchronized (delegate.getReloadLock())
 156  
         {
 157  33
             super.clearProperty(key);
 158  33
             delegate.possiblySave();
 159  33
         }
 160  33
     }
 161  
 
 162  
     @Override
 163  
     public void clearTree(String key)
 164  
     {
 165  1
         synchronized (delegate.getReloadLock())
 166  
         {
 167  1
             super.clearTree(key);
 168  1
             delegate.possiblySave();
 169  1
         }
 170  1
     }
 171  
 
 172  
     @Override
 173  
     public void setProperty(String key, Object value)
 174  
     {
 175  675
         synchronized (delegate.getReloadLock())
 176  
         {
 177  675
             super.setProperty(key, value);
 178  675
             delegate.possiblySave();
 179  675
         }
 180  675
     }
 181  
 
 182  
     public void load() throws ConfigurationException
 183  
     {
 184  657
         delegate.load();
 185  617
     }
 186  
 
 187  
     public void load(String fileName) throws ConfigurationException
 188  
     {
 189  2
         delegate.load(fileName);
 190  2
     }
 191  
 
 192  
     public void load(File file) throws ConfigurationException
 193  
     {
 194  12
         delegate.load(file);
 195  10
     }
 196  
 
 197  
     public void load(URL url) throws ConfigurationException
 198  
     {
 199  3
         delegate.load(url);
 200  3
     }
 201  
 
 202  
     public void load(InputStream in) throws ConfigurationException
 203  
     {
 204  0
         delegate.load(in);
 205  0
     }
 206  
 
 207  
     public void load(InputStream in, String encoding) throws ConfigurationException
 208  
     {
 209  1
         delegate.load(in, encoding);
 210  1
     }
 211  
 
 212  
     public void save() throws ConfigurationException
 213  
     {
 214  27
         delegate.save();
 215  27
     }
 216  
 
 217  
     public void save(String fileName) throws ConfigurationException
 218  
     {
 219  12
         delegate.save(fileName);
 220  12
     }
 221  
 
 222  
     public void save(File file) throws ConfigurationException
 223  
     {
 224  37
         delegate.save(file);
 225  36
     }
 226  
 
 227  
     public void save(URL url) throws ConfigurationException
 228  
     {
 229  1
         delegate.save(url);
 230  1
     }
 231  
 
 232  
     public void save(OutputStream out) throws ConfigurationException
 233  
     {
 234  1
         delegate.save(out);
 235  1
     }
 236  
 
 237  
     public void save(OutputStream out, String encoding) throws ConfigurationException
 238  
     {
 239  1
         delegate.save(out, encoding);
 240  1
     }
 241  
 
 242  
     public String getFileName()
 243  
     {
 244  7
         return delegate.getFileName();
 245  
     }
 246  
 
 247  
     public void setFileName(String fileName)
 248  
     {
 249  269
         delegate.setFileName(fileName);
 250  269
     }
 251  
 
 252  
     public String getBasePath()
 253  
     {
 254  325
         return delegate.getBasePath();
 255  
     }
 256  
 
 257  
     public void setBasePath(String basePath)
 258  
     {
 259  258
         delegate.setBasePath(basePath);
 260  258
     }
 261  
 
 262  
     public File getFile()
 263  
     {
 264  6
         return delegate.getFile();
 265  
     }
 266  
 
 267  
     public void setFile(File file)
 268  
     {
 269  392
         delegate.setFile(file);
 270  392
     }
 271  
 
 272  
     public URL getURL()
 273  
     {
 274  1
         return delegate.getURL();
 275  
     }
 276  
 
 277  
     public void setURL(URL url)
 278  
     {
 279  10
         delegate.setURL(url);
 280  10
     }
 281  
 
 282  
     public void setAutoSave(boolean autoSave)
 283  
     {
 284  5
         delegate.setAutoSave(autoSave);
 285  5
     }
 286  
 
 287  
     public boolean isAutoSave()
 288  
     {
 289  2
         return delegate.isAutoSave();
 290  
     }
 291  
 
 292  
     public ReloadingStrategy getReloadingStrategy()
 293  
     {
 294  5
         return delegate.getReloadingStrategy();
 295  
     }
 296  
 
 297  
     public void setReloadingStrategy(ReloadingStrategy strategy)
 298  
     {
 299  64
         delegate.setReloadingStrategy(strategy);
 300  64
     }
 301  
 
 302  
     public void reload()
 303  
     {
 304  428384
         reload(false);
 305  428414
     }
 306  
 
 307  
     private boolean reload(boolean checkReload)
 308  
     {
 309  852938
         synchronized (delegate.getReloadLock())
 310  
         {
 311  853154
             setDetailEvents(false);
 312  
             try
 313  
             {
 314  853374
                 return delegate.reload(checkReload);
 315  
             }
 316  
             finally
 317  
             {
 318  853074
                 setDetailEvents(true);
 319  
             }
 320  2
         }
 321  
     }
 322  
 
 323  
     /**
 324  
      * Reloads the associated configuration file. This method first clears the
 325  
      * content of this configuration, then the associated configuration file is
 326  
      * loaded again. Updates on this configuration which have not yet been saved
 327  
      * are lost. Calling this method is like invoking {@code reload()}
 328  
      * without checking the reloading strategy.
 329  
      *
 330  
      * @throws ConfigurationException if an error occurs
 331  
      * @since 1.7
 332  
      */
 333  
     public void refresh() throws ConfigurationException
 334  
     {
 335  2
         delegate.refresh();
 336  1
     }
 337  
 
 338  
     public String getEncoding()
 339  
     {
 340  93
         return delegate.getEncoding();
 341  
     }
 342  
 
 343  
     public void setEncoding(String encoding)
 344  
     {
 345  3
         delegate.setEncoding(encoding);
 346  3
     }
 347  
 
 348  
     @Override
 349  
     public Object getReloadLock()
 350  
     {
 351  10656
         return delegate.getReloadLock();
 352  
     }
 353  
 
 354  
     @Override
 355  
     public boolean containsKey(String key)
 356  
     {
 357  1198
         reload();
 358  1198
         synchronized (delegate.getReloadLock())
 359  
         {
 360  1198
             return super.containsKey(key);
 361  0
         }
 362  
     }
 363  
 
 364  
     @Override
 365  
     public Iterator<String> getKeys()
 366  
     {
 367  48
         reload();
 368  48
         synchronized (delegate.getReloadLock())
 369  
         {
 370  48
             return super.getKeys();
 371  0
         }
 372  
     }
 373  
 
 374  
     @Override
 375  
     public Iterator<String> getKeys(String prefix)
 376  
     {
 377  5
         reload();
 378  5
         synchronized (delegate.getReloadLock())
 379  
         {
 380  5
             return super.getKeys(prefix);
 381  0
         }
 382  
     }
 383  
 
 384  
     @Override
 385  
     public Object getProperty(String key)
 386  
     {
 387  424558
         if (reload(true))
 388  
         {
 389  
             // Avoid reloading again and getting the same error.
 390  424975
             synchronized (delegate.getReloadLock())
 391  
             {
 392  424986
                 return super.getProperty(key);
 393  0
             }
 394  
         }
 395  0
         return null;
 396  
     }
 397  
 
 398  
     @Override
 399  
     public boolean isEmpty()
 400  
     {
 401  14
         reload();
 402  14
         synchronized (delegate.getReloadLock())
 403  
         {
 404  14
             return super.isEmpty();
 405  0
         }
 406  
     }
 407  
 
 408  
     /**
 409  
      * Directly adds sub nodes to this configuration. This implementation checks
 410  
      * whether auto save is necessary after executing the operation.
 411  
      *
 412  
      * @param key the key where the nodes are to be added
 413  
      * @param nodes a collection with the nodes to be added
 414  
      * @since 1.5
 415  
      */
 416  
     @Override
 417  
     public void addNodes(String key, Collection<? extends ConfigurationNode> nodes)
 418  
     {
 419  5
         synchronized (delegate.getReloadLock())
 420  
         {
 421  5
             super.addNodes(key, nodes);
 422  5
             delegate.possiblySave();
 423  5
         }
 424  5
     }
 425  
 
 426  
     /**
 427  
      * Fetches a list of nodes, which are selected by the specified key. This
 428  
      * implementation will perform a reload if necessary.
 429  
      *
 430  
      * @param key the key
 431  
      * @return a list with the selected nodes
 432  
      */
 433  
     @Override
 434  
     protected List<ConfigurationNode> fetchNodeList(String key)
 435  
     {
 436  426598
         reload();
 437  426652
         synchronized (delegate.getReloadLock())
 438  
         {
 439  426615
             return super.fetchNodeList(key);
 440  0
         }
 441  
     }
 442  
 
 443  
     /**
 444  
      * Reacts on changes of an associated subnode configuration. If the auto
 445  
      * save mechanism is active, the configuration must be saved.
 446  
      *
 447  
      * @param event the event describing the change
 448  
      * @since 1.5
 449  
      */
 450  
     @Override
 451  
     protected void subnodeConfigurationChanged(ConfigurationEvent event)
 452  
     {
 453  24
         delegate.possiblySave();
 454  24
         super.subnodeConfigurationChanged(event);
 455  24
     }
 456  
 
 457  
     /**
 458  
      * Creates the file configuration delegate, i.e. the object that implements
 459  
      * functionality required by the {@code FileConfiguration} interface.
 460  
      * This base implementation will return an instance of the
 461  
      * {@code FileConfigurationDelegate} class. Derived classes may
 462  
      * override it to create a different delegate object.
 463  
      *
 464  
      * @return the file configuration delegate
 465  
      */
 466  
     protected FileConfigurationDelegate createDelegate()
 467  
     {
 468  413
         return new FileConfigurationDelegate();
 469  
     }
 470  
 
 471  
     /**
 472  
      * Helper method for initializing the file configuration delegate.
 473  
      *
 474  
      * @param del the delegate
 475  
      */
 476  
     private void initDelegate(FileConfigurationDelegate del)
 477  
     {
 478  1166
         del.addConfigurationListener(this);
 479  1166
         del.addErrorListener(this);
 480  1166
         del.setLogger(getLogger());
 481  1166
     }
 482  
 
 483  
     /**
 484  
      * Reacts on configuration change events triggered by the delegate. These
 485  
      * events are passed to the registered configuration listeners.
 486  
      *
 487  
      * @param event the triggered event
 488  
      * @since 1.3
 489  
      */
 490  
     public void configurationChanged(ConfigurationEvent event)
 491  
     {
 492  
         // deliver reload events to registered listeners
 493  24911
         setDetailEvents(true);
 494  
         try
 495  
         {
 496  25029
             fireEvent(event.getType(), event.getPropertyName(), event
 497  
                     .getPropertyValue(), event.isBeforeUpdate());
 498  
         }
 499  
         finally
 500  
         {
 501  24991
             setDetailEvents(false);
 502  25064
         }
 503  25058
     }
 504  
 
 505  
     public void configurationError(ConfigurationErrorEvent event)
 506  
     {
 507  2
         fireError(event.getType(), event.getPropertyName(), event.getPropertyValue(),
 508  
                 event.getCause());
 509  0
     }
 510  
 
 511  
     /**
 512  
      * Returns the file configuration delegate.
 513  
      *
 514  
      * @return the delegate
 515  
      */
 516  
     protected FileConfigurationDelegate getDelegate()
 517  
     {
 518  12952
         return delegate;
 519  
     }
 520  
 
 521  
     /**
 522  
      * Allows to set the file configuration delegate.
 523  
      * @param delegate the new delegate
 524  
      */
 525  
     protected void setDelegate(FileConfigurationDelegate delegate)
 526  
     {
 527  2
         this.delegate = delegate;
 528  2
     }
 529  
 
 530  
     /**
 531  
      * Set the FileSystem to be used for this Configuration.
 532  
      * @param fileSystem The FileSystem to use.
 533  
      */
 534  
     public void setFileSystem(FileSystem fileSystem)
 535  
     {
 536  221
         delegate.setFileSystem(fileSystem);
 537  221
     }
 538  
 
 539  
     /**
 540  
      * Reset the FileSystem to the default;
 541  
      */
 542  
     public void resetFileSystem()
 543  
     {
 544  0
         delegate.resetFileSystem();
 545  0
     }
 546  
 
 547  
     /**
 548  
      * Retrieve the FileSystem being used.
 549  
      * @return The FileSystem.
 550  
      */
 551  
     public FileSystem getFileSystem()
 552  
     {
 553  535
         return delegate.getFileSystem();
 554  
     }
 555  
 
 556  
     /**
 557  
      * A special implementation of the {@code FileConfiguration} interface that is
 558  
      * used internally to implement the {@code FileConfiguration} methods
 559  
      * for hierarchical configurations.
 560  
      */
 561  1168
     protected class FileConfigurationDelegate extends AbstractFileConfiguration
 562  
     {
 563  
         public void load(Reader in) throws ConfigurationException
 564  
         {
 565  60
             AbstractHierarchicalFileConfiguration.this.load(in);
 566  60
         }
 567  
 
 568  
         public void save(Writer out) throws ConfigurationException
 569  
         {
 570  87
             AbstractHierarchicalFileConfiguration.this.save(out);
 571  86
         }
 572  
 
 573  
         @Override
 574  
         public void clear()
 575  
         {
 576  12527
             AbstractHierarchicalFileConfiguration.this.clear();
 577  12525
         }
 578  
     }
 579  
 }