Coverage Report - org.apache.commons.configuration.MultiFileHierarchicalConfiguration
 
Classes in this File Line Coverage Branch Coverage Complexity
MultiFileHierarchicalConfiguration
22%
40/182
40%
6/15
1,337
MultiFileHierarchicalConfiguration$1
50%
1/2
N/A
1,337
MultiFileHierarchicalConfiguration$2
0%
0/3
N/A
1,337
 
 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  
 package org.apache.commons.configuration;
 18  
 
 19  
 import java.io.File;
 20  
 import java.io.FileNotFoundException;
 21  
 import java.io.InputStream;
 22  
 import java.io.OutputStream;
 23  
 import java.io.Reader;
 24  
 import java.io.Writer;
 25  
 import java.math.BigDecimal;
 26  
 import java.math.BigInteger;
 27  
 import java.net.MalformedURLException;
 28  
 import java.net.URL;
 29  
 import java.util.Collection;
 30  
 import java.util.HashMap;
 31  
 import java.util.Iterator;
 32  
 import java.util.List;
 33  
 import java.util.Map;
 34  
 import java.util.Properties;
 35  
 
 36  
 import org.apache.commons.configuration.event.ConfigurationErrorEvent;
 37  
 import org.apache.commons.configuration.event.ConfigurationErrorListener;
 38  
 import org.apache.commons.configuration.event.ConfigurationEvent;
 39  
 import org.apache.commons.configuration.event.ConfigurationListener;
 40  
 import org.apache.commons.configuration.tree.ConfigurationNode;
 41  
 import org.apache.commons.configuration.tree.ExpressionEngine;
 42  
 
 43  
 /**
 44  
  * This class provides access to multiple configuration files that reside in a location that
 45  
  * can be specified by a pattern allowing applications to be multi-tenant.  For example,
 46  
  * providing a pattern of "file:///opt/config/${product}/${client}/config.xml" will result in
 47  
  * "product" and "client" being resolved on every call. The configuration resulting from the
 48  
  * resolved pattern will be saved for future access.
 49  
  * @since 1.6
 50  
  * @author <a
 51  
  * href="http://commons.apache.org/configuration/team-list.html">Commons
 52  
  * Configuration team</a>
 53  
  * @version $Id: MultiFileHierarchicalConfiguration.java 727958 2008-12-19 07:19:24Z oheger $
 54  
  */
 55  
 public class MultiFileHierarchicalConfiguration extends AbstractHierarchicalFileConfiguration
 56  
     implements ConfigurationListener, ConfigurationErrorListener
 57  
 {
 58  
     /** FILE URL prefix */
 59  
     private static final String FILE_URL_PREFIX = "file:";
 60  
 
 61  
     /**
 62  
      * Prevent recursion while resolving unprefixed properties.
 63  
      */
 64  2
     private static ThreadLocal recursive = new ThreadLocal()
 65  
     {
 66  2
         protected synchronized Object initialValue()
 67  
         {
 68  0
             return Boolean.FALSE;
 69  
         }
 70  
     };
 71  
 
 72  
     /** Map of configurations */
 73  2
     private final Map configurationsMap = new HashMap();
 74  
 
 75  
     /** key pattern for configurationsMap */
 76  
     private String pattern;
 77  
 
 78  
     /** True if the constructor has finished */
 79  
     private boolean init;
 80  
 
 81  
     /**
 82  
      * Default Constructor.
 83  
      */
 84  
     public MultiFileHierarchicalConfiguration()
 85  
     {
 86  0
         super();
 87  0
         this.init = true;
 88  0
     }
 89  
 
 90  
     /**
 91  
      * Construct the configuration with the specified pattern.
 92  
      * @param pathPattern The pattern to use to locate configuration files.
 93  
      */
 94  
     public MultiFileHierarchicalConfiguration(String pathPattern)
 95  
     {
 96  2
         super();
 97  2
         this.pattern = pathPattern;
 98  2
         this.init = true;
 99  2
     }
 100  
 
 101  
     /**
 102  
      * Set the File pattern
 103  
      * @param pathPattern The pattern for the path to the configuration.
 104  
      */
 105  
     public void setFilePattern(String pathPattern)
 106  
     {
 107  0
         this.pattern = pathPattern;
 108  0
     }
 109  
 
 110  
     /**
 111  
      * Creates the file configuration delegate, i.e. the object that implements
 112  
      * functionality required by the <code>FileConfiguration</code> interface.
 113  
      * This base implementation will return an instance of the
 114  
      * <code>FileConfigurationDelegate</code> class. Derived classes may
 115  
      * override it to create a different delegate object.
 116  
      *
 117  
      * @return the file configuration delegate
 118  
      */
 119  
     protected FileConfigurationDelegate createDelegate()
 120  
     {
 121  2
         return new FileConfigurationDelegate();
 122  
     }
 123  
 
 124  
     public void addProperty(String key, Object value)
 125  
     {
 126  0
         this.getConfiguration().addProperty(key, value);
 127  0
     }
 128  
 
 129  
     public void clear()
 130  
     {
 131  0
         this.getConfiguration().clear();
 132  0
     }
 133  
 
 134  
     public void clearProperty(String key)
 135  
     {
 136  0
         this.getConfiguration().clearProperty(key);
 137  0
     }
 138  
 
 139  
     public boolean containsKey(String key)
 140  
     {
 141  0
         return this.getConfiguration().containsKey(key);
 142  
     }
 143  
 
 144  
     public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
 145  
     {
 146  0
         return this.getConfiguration().getBigDecimal(key, defaultValue);
 147  
     }
 148  
 
 149  
     public BigDecimal getBigDecimal(String key)
 150  
     {
 151  0
         return this.getConfiguration().getBigDecimal(key);
 152  
     }
 153  
 
 154  
     public BigInteger getBigInteger(String key, BigInteger defaultValue)
 155  
     {
 156  0
         return this.getConfiguration().getBigInteger(key, defaultValue);
 157  
     }
 158  
 
 159  
     public BigInteger getBigInteger(String key)
 160  
     {
 161  0
         return this.getConfiguration().getBigInteger(key);
 162  
     }
 163  
 
 164  
     public boolean getBoolean(String key, boolean defaultValue)
 165  
     {
 166  0
         return this.getConfiguration().getBoolean(key, defaultValue);
 167  
     }
 168  
 
 169  
     public Boolean getBoolean(String key, Boolean defaultValue)
 170  
     {
 171  0
         return this.getConfiguration().getBoolean(key, defaultValue);
 172  
     }
 173  
 
 174  
     public boolean getBoolean(String key)
 175  
     {
 176  0
         return this.getConfiguration().getBoolean(key);
 177  
     }
 178  
 
 179  
     public byte getByte(String key, byte defaultValue)
 180  
     {
 181  0
         return this.getConfiguration().getByte(key, defaultValue);
 182  
     }
 183  
 
 184  
     public Byte getByte(String key, Byte defaultValue)
 185  
     {
 186  0
         return this.getConfiguration().getByte(key, defaultValue);
 187  
     }
 188  
 
 189  
     public byte getByte(String key)
 190  
     {
 191  0
         return this.getConfiguration().getByte(key);
 192  
     }
 193  
 
 194  
     public double getDouble(String key, double defaultValue)
 195  
     {
 196  0
         return this.getConfiguration().getDouble(key, defaultValue);
 197  
     }
 198  
 
 199  
     public Double getDouble(String key, Double defaultValue)
 200  
     {
 201  0
         return this.getConfiguration().getDouble(key, defaultValue);
 202  
     }
 203  
 
 204  
     public double getDouble(String key)
 205  
     {
 206  0
         return this.getConfiguration().getDouble(key);
 207  
     }
 208  
 
 209  
     public float getFloat(String key, float defaultValue)
 210  
     {
 211  0
         return this.getConfiguration().getFloat(key, defaultValue);
 212  
     }
 213  
 
 214  
     public Float getFloat(String key, Float defaultValue)
 215  
     {
 216  0
         return this.getConfiguration().getFloat(key, defaultValue);
 217  
     }
 218  
 
 219  
     public float getFloat(String key)
 220  
     {
 221  0
         return this.getConfiguration().getFloat(key);
 222  
     }
 223  
 
 224  
     public int getInt(String key, int defaultValue)
 225  
     {
 226  0
         return this.getConfiguration().getInt(key, defaultValue);
 227  
     }
 228  
 
 229  
     public int getInt(String key)
 230  
     {
 231  3
         return this.getConfiguration().getInt(key);
 232  
     }
 233  
 
 234  
     public Integer getInteger(String key, Integer defaultValue)
 235  
     {
 236  0
         return this.getConfiguration().getInteger(key, defaultValue);
 237  
     }
 238  
 
 239  
     public Iterator getKeys()
 240  
     {
 241  0
         return this.getConfiguration().getKeys();
 242  
     }
 243  
 
 244  
     public Iterator getKeys(String prefix)
 245  
     {
 246  0
         return this.getConfiguration().getKeys(prefix);
 247  
     }
 248  
 
 249  
     public List getList(String key, List defaultValue)
 250  
     {
 251  0
         return this.getConfiguration().getList(key, defaultValue);
 252  
     }
 253  
 
 254  
     public List getList(String key)
 255  
     {
 256  0
         return this.getConfiguration().getList(key);
 257  
     }
 258  
 
 259  
     public long getLong(String key, long defaultValue)
 260  
     {
 261  0
         return this.getConfiguration().getLong(key, defaultValue);
 262  
     }
 263  
 
 264  
     public Long getLong(String key, Long defaultValue)
 265  
     {
 266  0
         return this.getConfiguration().getLong(key, defaultValue);
 267  
     }
 268  
 
 269  
     public long getLong(String key)
 270  
     {
 271  0
         return this.getConfiguration().getLong(key);
 272  
     }
 273  
 
 274  
     public Properties getProperties(String key)
 275  
     {
 276  0
         return this.getConfiguration().getProperties(key);
 277  
     }
 278  
 
 279  
     public Object getProperty(String key)
 280  
     {
 281  0
         return this.getConfiguration().getProperty(key);
 282  
     }
 283  
 
 284  
     public short getShort(String key, short defaultValue)
 285  
     {
 286  0
         return this.getConfiguration().getShort(key, defaultValue);
 287  
     }
 288  
 
 289  
     public Short getShort(String key, Short defaultValue)
 290  
     {
 291  0
         return this.getConfiguration().getShort(key, defaultValue);
 292  
     }
 293  
 
 294  
     public short getShort(String key)
 295  
     {
 296  0
         return this.getConfiguration().getShort(key);
 297  
     }
 298  
 
 299  
     public String getString(String key, String defaultValue)
 300  
     {
 301  0
         return this.getConfiguration().getString(key, defaultValue);
 302  
     }
 303  
 
 304  
     public String getString(String key)
 305  
     {
 306  0
         return this.getConfiguration().getString(key);
 307  
     }
 308  
 
 309  
     public String[] getStringArray(String key)
 310  
     {
 311  0
         return this.getConfiguration().getStringArray(key);
 312  
     }
 313  
 
 314  
     public boolean isEmpty()
 315  
     {
 316  0
         return this.getConfiguration().isEmpty();
 317  
     }
 318  
 
 319  
     public void setProperty(String key, Object value)
 320  
     {
 321  0
         if (init)
 322  
         {
 323  0
             this.getConfiguration().setProperty(key, value);
 324  
         }
 325  0
     }
 326  
 
 327  
     public Configuration subset(String prefix)
 328  
     {
 329  0
         return this.getConfiguration().subset(prefix);
 330  
     }
 331  
 
 332  
     public Node getRoot()
 333  
     {
 334  0
         return this.getConfiguration().getRoot();
 335  
     }
 336  
 
 337  
     public void setRoot(Node node)
 338  
     {
 339  0
         if (init)
 340  
         {
 341  0
             this.getConfiguration().setRoot(node);
 342  
         }
 343  
         else
 344  
         {
 345  0
             super.setRoot(node);
 346  
         }
 347  0
     }
 348  
 
 349  
     public ConfigurationNode getRootNode()
 350  
     {
 351  12
         return this.getConfiguration().getRootNode();
 352  
     }
 353  
 
 354  
     public void setRootNode(ConfigurationNode rootNode)
 355  
     {
 356  2
         if (init)
 357  
         {
 358  0
             this.getConfiguration().setRootNode(rootNode);
 359  
         }
 360  
         else
 361  
         {
 362  2
             super.setRootNode(rootNode);
 363  
         }
 364  2
     }
 365  
 
 366  
     public ExpressionEngine getExpressionEngine()
 367  
     {
 368  7
         return super.getExpressionEngine();
 369  
     }
 370  
 
 371  
     public void setExpressionEngine(ExpressionEngine expressionEngine)
 372  
     {
 373  0
         super.setExpressionEngine(expressionEngine);
 374  0
     }
 375  
 
 376  
     public void addNodes(String key, Collection nodes)
 377  
     {
 378  0
         this.getConfiguration().addNodes(key, nodes);
 379  0
     }
 380  
 
 381  
     public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
 382  
     {
 383  0
         return this.getConfiguration().configurationAt(key, supportUpdates);
 384  
     }
 385  
 
 386  
     public SubnodeConfiguration configurationAt(String key)
 387  
     {
 388  0
         return this.getConfiguration().configurationAt(key);
 389  
     }
 390  
 
 391  
     public List configurationsAt(String key)
 392  
     {
 393  0
         return this.getConfiguration().configurationsAt(key);
 394  
     }
 395  
 
 396  
     public void clearTree(String key)
 397  
     {
 398  0
         this.getConfiguration().clearTree(key);
 399  0
     }
 400  
 
 401  
     public int getMaxIndex(String key)
 402  
     {
 403  0
         return this.getConfiguration().getMaxIndex(key);
 404  
     }
 405  
 
 406  
     public Configuration interpolatedConfiguration()
 407  
     {
 408  0
         return this.getConfiguration().interpolatedConfiguration();
 409  
     }
 410  
 
 411  
     public void addConfigurationListener(ConfigurationListener l)
 412  
     {
 413  4
         super.addConfigurationListener(l);
 414  4
     }
 415  
 
 416  
     public boolean removeConfigurationListener(ConfigurationListener l)
 417  
     {
 418  0
         return super.removeConfigurationListener(l);
 419  
     }
 420  
 
 421  
     public Collection getConfigurationListeners()
 422  
     {
 423  0
         return super.getConfigurationListeners();
 424  
     }
 425  
 
 426  
     public void clearConfigurationListeners()
 427  
     {
 428  0
         super.clearConfigurationListeners();
 429  0
     }
 430  
 
 431  
     public void addErrorListener(ConfigurationErrorListener l)
 432  
     {
 433  0
         super.addErrorListener(l);
 434  0
     }
 435  
 
 436  
     public boolean removeErrorListener(ConfigurationErrorListener l)
 437  
     {
 438  0
         return super.removeErrorListener(l);
 439  
     }
 440  
 
 441  
     public void clearErrorListeners()
 442  
     {
 443  0
         super.clearErrorListeners();
 444  0
     }
 445  
 
 446  
     public Collection getErrorListeners()
 447  
     {
 448  0
         return super.getErrorListeners();
 449  
     }
 450  
 
 451  
     public void save(Writer writer) throws ConfigurationException
 452  
     {
 453  0
         if (init)
 454  
         {
 455  0
             this.getConfiguration().save(writer);
 456  
         }
 457  0
     }
 458  
 
 459  
     public void load(Reader reader) throws ConfigurationException
 460  
     {
 461  0
         if (init)
 462  
         {
 463  0
             this.getConfiguration().load(reader);
 464  
         }
 465  0
     }
 466  
 
 467  
     public void load() throws ConfigurationException
 468  
     {
 469  0
         this.getConfiguration().load();
 470  0
     }
 471  
 
 472  
     public void load(String fileName) throws ConfigurationException
 473  
     {
 474  0
         this.getConfiguration().load(fileName);
 475  0
     }
 476  
 
 477  
     public void load(File file) throws ConfigurationException
 478  
     {
 479  0
         this.getConfiguration().load(file);
 480  0
     }
 481  
 
 482  
     public void load(URL url) throws ConfigurationException
 483  
     {
 484  0
         this.getConfiguration().load(url);
 485  0
     }
 486  
 
 487  
     public void load(InputStream in) throws ConfigurationException
 488  
     {
 489  0
         this.getConfiguration().load(in);
 490  0
     }
 491  
 
 492  
     public void load(InputStream in, String encoding) throws ConfigurationException
 493  
     {
 494  0
         this.getConfiguration().load(in, encoding);
 495  0
     }
 496  
 
 497  
     public void save() throws ConfigurationException
 498  
     {
 499  0
         this.getConfiguration().save();
 500  0
     }
 501  
 
 502  
     public void save(String fileName) throws ConfigurationException
 503  
     {
 504  0
         this.getConfiguration().save(fileName);
 505  0
     }
 506  
 
 507  
     public void save(File file) throws ConfigurationException
 508  
     {
 509  0
         this.getConfiguration().save(file);
 510  0
     }
 511  
 
 512  
     public void save(URL url) throws ConfigurationException
 513  
     {
 514  0
         this.getConfiguration().save(url);
 515  0
     }
 516  
 
 517  
     public void save(OutputStream out) throws ConfigurationException
 518  
     {
 519  0
         this.getConfiguration().save(out);
 520  0
     }
 521  
 
 522  
     public void save(OutputStream out, String encoding) throws ConfigurationException
 523  
     {
 524  0
         this.getConfiguration().save(out, encoding);
 525  0
     }
 526  
 
 527  
     public void configurationChanged(ConfigurationEvent event)
 528  
     {
 529  0
         if (event.getSource() instanceof XMLConfiguration)
 530  
         {
 531  0
             Iterator iter = getConfigurationListeners().iterator();
 532  0
             while (iter.hasNext())
 533  
             {
 534  0
                 ConfigurationListener listener = (ConfigurationListener) iter.next();
 535  0
                 listener.configurationChanged(event);
 536  
             }
 537  
         }
 538  0
     }
 539  
 
 540  
     public void configurationError(ConfigurationErrorEvent event)
 541  
     {
 542  0
         if (event.getSource() instanceof XMLConfiguration)
 543  
         {
 544  0
             Iterator iter = getErrorListeners().iterator();
 545  0
             while (iter.hasNext())
 546  
             {
 547  0
                 ConfigurationErrorListener listener = (ConfigurationErrorListener) iter.next();
 548  0
                 listener.configurationError(event);
 549  
             }
 550  
         }
 551  0
     }
 552  
 
 553  
     /*
 554  
      * Don't allow resolveContainerStore to be called recursively.
 555  
      * @param key The key to resolve.
 556  
      * @return The value of the key.
 557  
      */
 558  
     protected Object resolveContainerStore(String key)
 559  
     {
 560  0
         if (((Boolean) recursive.get()).booleanValue())
 561  
         {
 562  0
             return null;
 563  
         }
 564  0
         recursive.set(Boolean.TRUE);
 565  
         try
 566  
         {
 567  0
             return super.resolveContainerStore(key);
 568  
         }
 569  
         finally
 570  
         {
 571  0
             recursive.set(Boolean.FALSE);
 572  
         }
 573  
     }
 574  
 
 575  
     /**
 576  
      * Remove the current Configuration.
 577  
      */
 578  
     public void removeConfiguration()
 579  
     {
 580  0
         String path = getSubstitutor().replace(pattern);
 581  0
         synchronized (configurationsMap)
 582  
         {
 583  0
             configurationsMap.remove(path);
 584  0
         }
 585  0
     }
 586  
 
 587  
     /**
 588  
      * First checks to see if the cache exists, if it does, get the associated Configuration.
 589  
      * If not it will load a new Configuration and save it in the cache.
 590  
      *
 591  
      * @return the Configuration associated with the current value of the path pattern.
 592  
      */
 593  
     private AbstractHierarchicalFileConfiguration getConfiguration()
 594  
     {
 595  15
         if (pattern == null)
 596  
         {
 597  0
             throw new ConfigurationRuntimeException("File pattern must be defined");
 598  
         }
 599  15
         String path = getSubstitutor().replace(pattern);
 600  15
         synchronized (configurationsMap)
 601  
         {
 602  15
             if (configurationsMap.containsKey(path))
 603  
             {
 604  8
                 return (AbstractHierarchicalFileConfiguration) configurationsMap.get(path);
 605  
             }
 606  7
         }
 607  
 
 608  7
         if (path.equals(pattern))
 609  
         {
 610  0
             XMLConfiguration configuration = new XMLConfiguration()
 611  
             {
 612  
                 public void load() throws ConfigurationException
 613  
                 {
 614  0
                 }
 615  0
                 public void save() throws ConfigurationException
 616  
                 {
 617  0
                 }
 618  
             };
 619  0
             synchronized (configurationsMap)
 620  
             {
 621  0
                 configurationsMap.put(pattern, configuration);
 622  0
             }
 623  0
             return configuration;
 624  
         }
 625  
 
 626  7
         XMLConfiguration configuration = new XMLConfiguration();
 627  
         try
 628  
         {
 629  7
             URL url = getURL(path);
 630  7
             configuration.setURL(url);
 631  7
             configuration.load();
 632  7
             configuration.setExpressionEngine(getExpressionEngine());
 633  7
             configuration.setReloadingStrategy(getReloadingStrategy());
 634  7
             configuration.addConfigurationListener(this);
 635  7
             configuration.addErrorListener(this);
 636  7
             synchronized (configurationsMap)
 637  
             {
 638  7
                 if (!configurationsMap.containsKey(path))
 639  
                 {
 640  7
                     configurationsMap.put(path, configuration);
 641  
                 }
 642  7
             }
 643  
         }
 644  0
         catch (ConfigurationException ce)
 645  
         {
 646  0
             throw new ConfigurationRuntimeException(ce);
 647  
         }
 648  0
         catch (FileNotFoundException fnfe)
 649  
         {
 650  0
             throw new ConfigurationRuntimeException(fnfe);
 651  7
         }
 652  
 
 653  7
         return configuration;
 654  
     }
 655  
 
 656  
     private URL getURL(String resourceLocation) throws FileNotFoundException
 657  
     {
 658  7
         if (resourceLocation == null)
 659  
         {
 660  0
             throw new IllegalArgumentException("A path pattern must be configured");
 661  
         }
 662  
         try
 663  
         {
 664  
             // try URL
 665  7
             return new URL(resourceLocation);
 666  
         }
 667  7
         catch (MalformedURLException ex)
 668  
         {
 669  
             // no URL -> treat as file path
 670  
             try
 671  
             {
 672  7
                 return new URL(FILE_URL_PREFIX + resourceLocation);
 673  
             }
 674  0
             catch (MalformedURLException ex2)
 675  
             {
 676  0
                 throw new FileNotFoundException("Resource location [" + resourceLocation
 677  
                         + "] is not a URL or a well-formed file path");
 678  
             }
 679  
         }
 680  
     }
 681  
 }