View Javadoc

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.ConfigurationEvent;
31  import org.apache.commons.configuration.event.ConfigurationListener;
32  import org.apache.commons.configuration.reloading.ReloadingStrategy;
33  
34  /***
35   * <p>Base class for implementing file based hierarchical configurations.</p>
36   * <p>This class serves an analogous purpose as the
37   * <code>{@link AbstractFileConfiguration}</code> class for non hierarchical
38   * configurations. It behaves in exactly the same way, so please refer to the
39   * documentation of <code>AbstractFileConfiguration</code> for further details.</p>
40   *
41   * @since 1.2
42   *
43   * @author Emmanuel Bourg
44   * @version $Revision: 712405 $, $Date: 2008-11-08 17:37:48 +0100 (Sa, 08 Nov 2008) $
45   */
46  public abstract class AbstractHierarchicalFileConfiguration
47  extends HierarchicalConfiguration
48  implements FileConfiguration, ConfigurationListener
49  {
50      /*** Stores the delegate used for implementing functionality related to the
51       * <code>FileConfiguration</code> interface.
52       */
53      private FileConfigurationDelegate delegate;
54  
55      /***
56       * Creates a new instance of
57       * <code>AbstractHierarchicalFileConfiguration</code>.
58       */
59      protected AbstractHierarchicalFileConfiguration()
60      {
61          initialize();
62      }
63  
64      /***
65       * Creates a new instance of
66       * <code>AbstractHierarchicalFileConfiguration</code> and copies the
67       * content of the specified configuration into this object.
68       *
69       * @param c the configuration to copy
70       * @since 1.4
71       */
72      protected AbstractHierarchicalFileConfiguration(HierarchicalConfiguration c)
73      {
74          super(c);
75          initialize();
76      }
77  
78      /***
79       * Creates and loads the configuration from the specified file.
80       *
81       * @param fileName The name of the plist file to load.
82       * @throws ConfigurationException Error while loading the file
83       */
84      public AbstractHierarchicalFileConfiguration(String fileName) throws ConfigurationException
85      {
86          this();
87          // store the file name
88          delegate.setFileName(fileName);
89  
90          // load the file
91          load();
92      }
93  
94      /***
95       * Creates and loads the configuration from the specified file.
96       *
97       * @param file The configuration file to load.
98       * @throws ConfigurationException Error while loading the file
99       */
100     public AbstractHierarchicalFileConfiguration(File file) throws ConfigurationException
101     {
102         this();
103         // set the file and update the url, the base path and the file name
104         setFile(file);
105 
106         // load the file
107         if (file.exists())
108         {
109             load();
110         }
111     }
112 
113     /***
114      * Creates and loads the configuration from the specified URL.
115      *
116      * @param url The location of the configuration file to load.
117      * @throws ConfigurationException Error while loading the file
118      */
119     public AbstractHierarchicalFileConfiguration(URL url) throws ConfigurationException
120     {
121         this();
122         // set the URL and update the base path and the file name
123         setURL(url);
124 
125         // load the file
126         load();
127     }
128 
129     /***
130      * Initializes this instance, mainly the internally used delegate object.
131      */
132     private void initialize()
133     {
134         delegate = createDelegate();
135         initDelegate(delegate);
136     }
137 
138     protected void addPropertyDirect(String key, Object obj)
139     {
140         super.addPropertyDirect(key, obj);
141         delegate.possiblySave();
142     }
143 
144     public void clearProperty(String key)
145     {
146         super.clearProperty(key);
147         delegate.possiblySave();
148     }
149 
150     public void clearTree(String key)
151     {
152         super.clearTree(key);
153         delegate.possiblySave();
154     }
155 
156     public void setProperty(String key, Object value)
157     {
158         super.setProperty(key, value);
159         delegate.possiblySave();
160     }
161 
162     public void load() throws ConfigurationException
163     {
164         delegate.load();
165     }
166 
167     public void load(String fileName) throws ConfigurationException
168     {
169         delegate.load(fileName);
170     }
171 
172     public void load(File file) throws ConfigurationException
173     {
174         delegate.load(file);
175     }
176 
177     public void load(URL url) throws ConfigurationException
178     {
179         delegate.load(url);
180     }
181 
182     public void load(InputStream in) throws ConfigurationException
183     {
184         delegate.load(in);
185     }
186 
187     public void load(InputStream in, String encoding) throws ConfigurationException
188     {
189         delegate.load(in, encoding);
190     }
191 
192     public void save() throws ConfigurationException
193     {
194         delegate.save();
195     }
196 
197     public void save(String fileName) throws ConfigurationException
198     {
199         delegate.save(fileName);
200     }
201 
202     public void save(File file) throws ConfigurationException
203     {
204         delegate.save(file);
205     }
206 
207     public void save(URL url) throws ConfigurationException
208     {
209         delegate.save(url);
210     }
211 
212     public void save(OutputStream out) throws ConfigurationException
213     {
214         delegate.save(out);
215     }
216 
217     public void save(OutputStream out, String encoding) throws ConfigurationException
218     {
219         delegate.save(out, encoding);
220     }
221 
222     public String getFileName()
223     {
224         return delegate.getFileName();
225     }
226 
227     public void setFileName(String fileName)
228     {
229         delegate.setFileName(fileName);
230     }
231 
232     public String getBasePath()
233     {
234         return delegate.getBasePath();
235     }
236 
237     public void setBasePath(String basePath)
238     {
239         delegate.setBasePath(basePath);
240     }
241 
242     public File getFile()
243     {
244         return delegate.getFile();
245     }
246 
247     public void setFile(File file)
248     {
249         delegate.setFile(file);
250     }
251 
252     public URL getURL()
253     {
254         return delegate.getURL();
255     }
256 
257     public void setURL(URL url)
258     {
259         delegate.setURL(url);
260     }
261 
262     public void setAutoSave(boolean autoSave)
263     {
264         delegate.setAutoSave(autoSave);
265     }
266 
267     public boolean isAutoSave()
268     {
269         return delegate.isAutoSave();
270     }
271 
272     public ReloadingStrategy getReloadingStrategy()
273     {
274         return delegate.getReloadingStrategy();
275     }
276 
277     public void setReloadingStrategy(ReloadingStrategy strategy)
278     {
279         delegate.setReloadingStrategy(strategy);
280     }
281 
282     public void reload()
283     {
284         setDetailEvents(false);
285         try
286         {
287             delegate.reload();
288         }
289         finally
290         {
291             setDetailEvents(true);
292         }
293     }
294 
295     public String getEncoding()
296     {
297         return delegate.getEncoding();
298     }
299 
300     public void setEncoding(String encoding)
301     {
302         delegate.setEncoding(encoding);
303     }
304 
305     public boolean containsKey(String key)
306     {
307         reload();
308         return super.containsKey(key);
309     }
310 
311     public Iterator getKeys()
312     {
313         reload();
314         return super.getKeys();
315     }
316 
317     public Iterator getKeys(String prefix)
318     {
319         reload();
320         return super.getKeys(prefix);
321     }
322 
323     public Object getProperty(String key)
324     {
325         reload();
326         return super.getProperty(key);
327     }
328 
329     public boolean isEmpty()
330     {
331         reload();
332         return super.isEmpty();
333     }
334 
335     /***
336      * Directly adds sub nodes to this configuration. This implementation checks
337      * whether auto save is necessary after executing the operation.
338      *
339      * @param key the key where the nodes are to be added
340      * @param nodes a collection with the nodes to be added
341      * @since 1.5
342      */
343     public void addNodes(String key, Collection nodes)
344     {
345         super.addNodes(key, nodes);
346         delegate.possiblySave();
347     }
348 
349     /***
350      * Fetches a list of nodes, which are selected by the specified key. This
351      * implementation will perform a reload if necessary.
352      *
353      * @param key the key
354      * @return a list with the selected nodes
355      */
356     protected List fetchNodeList(String key)
357     {
358         reload();
359         return super.fetchNodeList(key);
360     }
361 
362     /***
363      * Reacts on changes of an associated subnode configuration. If the auto
364      * save mechanism is active, the configuration must be saved.
365      *
366      * @param event the event describing the change
367      * @since 1.5
368      */
369     protected void subnodeConfigurationChanged(ConfigurationEvent event)
370     {
371         delegate.possiblySave();
372         super.subnodeConfigurationChanged(event);
373     }
374 
375     /***
376      * Creates the file configuration delegate, i.e. the object that implements
377      * functionality required by the <code>FileConfiguration</code> interface.
378      * This base implementation will return an instance of the
379      * <code>FileConfigurationDelegate</code> class. Derived classes may
380      * override it to create a different delegate object.
381      *
382      * @return the file configuration delegate
383      */
384     protected FileConfigurationDelegate createDelegate()
385     {
386         return new FileConfigurationDelegate();
387     }
388 
389     /***
390      * Helper method for initializing the file configuration delegate.
391      *
392      * @param del the delegate
393      */
394     private void initDelegate(FileConfigurationDelegate del)
395     {
396         del.addConfigurationListener(this);
397     }
398 
399     /***
400      * Reacts on configuration change events triggered by the delegate. These
401      * events are passed to the registered configuration listeners.
402      *
403      * @param event the triggered event
404      * @since 1.3
405      */
406     public void configurationChanged(ConfigurationEvent event)
407     {
408         // deliver reload events to registered listeners
409         setDetailEvents(true);
410         try
411         {
412             fireEvent(event.getType(), event.getPropertyName(), event
413                     .getPropertyValue(), event.isBeforeUpdate());
414         }
415         finally
416         {
417             setDetailEvents(false);
418         }
419     }
420 
421     /***
422      * Returns the file configuration delegate.
423      *
424      * @return the delegate
425      */
426     protected FileConfigurationDelegate getDelegate()
427     {
428         return delegate;
429     }
430 
431     /***
432      * Allows to set the file configuration delegate.
433      * @param delegate the new delegate
434      */
435     protected void setDelegate(FileConfigurationDelegate delegate)
436     {
437         this.delegate = delegate;
438     }
439 
440     /***
441      * A special implementation of the <code>FileConfiguration</code> interface that is
442      * used internally to implement the <code>FileConfiguration</code> methods
443      * for hierarchical configurations.
444      */
445     protected class FileConfigurationDelegate extends AbstractFileConfiguration
446     {
447         public void load(Reader in) throws ConfigurationException
448         {
449             AbstractHierarchicalFileConfiguration.this.load(in);
450         }
451 
452         public void save(Writer out) throws ConfigurationException
453         {
454             AbstractHierarchicalFileConfiguration.this.save(out);
455         }
456 
457         public void clear()
458         {
459             AbstractHierarchicalFileConfiguration.this.clear();
460         }
461     }
462 }