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.Reader;
21  import java.io.Writer;
22  import java.io.File;
23  import java.io.InputStream;
24  import java.io.OutputStream;
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: 589380 $, $Date: 2007-10-28 17:37:35 +0100 (So, 28 Okt 2007) $
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(String prefix)
312     {
313         reload();
314         return super.getKeys(prefix);
315     }
316 
317     public Object getProperty(String key)
318     {
319         reload();
320         return super.getProperty(key);
321     }
322 
323     public boolean isEmpty()
324     {
325         reload();
326         return super.isEmpty();
327     }
328 
329     /***
330      * Directly adds sub nodes to this configuration. This implementation checks
331      * whether auto save is necessary after executing the operation.
332      *
333      * @param key the key where the nodes are to be added
334      * @param nodes a collection with the nodes to be added
335      * @since 1.5
336      */
337     public void addNodes(String key, Collection nodes)
338     {
339         super.addNodes(key, nodes);
340         delegate.possiblySave();
341     }
342 
343     /***
344      * Fetches a list of nodes, which are selected by the specified key. This
345      * implementation will perform a reload if necessary.
346      *
347      * @param key the key
348      * @return a list with the selected nodes
349      */
350     protected List fetchNodeList(String key)
351     {
352         reload();
353         return super.fetchNodeList(key);
354     }
355 
356     /***
357      * Reacts on changes of an associated subnode configuration. If the auto
358      * save mechanism is active, the configuration must be saved.
359      *
360      * @param event the event describing the change
361      * @since 1.5
362      */
363     protected void subnodeConfigurationChanged(ConfigurationEvent event)
364     {
365         delegate.possiblySave();
366         super.subnodeConfigurationChanged(event);
367     }
368 
369     /***
370      * Creates the file configuration delegate, i.e. the object that implements
371      * functionality required by the <code>FileConfiguration</code> interface.
372      * This base implementation will return an instance of the
373      * <code>FileConfigurationDelegate</code> class. Derived classes may
374      * override it to create a different delegate object.
375      *
376      * @return the file configuration delegate
377      */
378     protected FileConfigurationDelegate createDelegate()
379     {
380         return new FileConfigurationDelegate();
381     }
382 
383     /***
384      * Helper method for initializing the file configuration delegate.
385      *
386      * @param del the delegate
387      */
388     private void initDelegate(FileConfigurationDelegate del)
389     {
390         del.addConfigurationListener(this);
391     }
392 
393     /***
394      * Reacts on configuration change events triggered by the delegate. These
395      * events are passed to the registered configuration listeners.
396      *
397      * @param event the triggered event
398      * @since 1.3
399      */
400     public void configurationChanged(ConfigurationEvent event)
401     {
402         // deliver reload events to registered listeners
403         setDetailEvents(true);
404         try
405         {
406             fireEvent(event.getType(), event.getPropertyName(), event
407                     .getPropertyValue(), event.isBeforeUpdate());
408         }
409         finally
410         {
411             setDetailEvents(false);
412         }
413     }
414 
415     /***
416      * Returns the file configuration delegate.
417      *
418      * @return the delegate
419      */
420     protected FileConfigurationDelegate getDelegate()
421     {
422         return delegate;
423     }
424 
425     /***
426      * Allows to set the file configuration delegate.
427      * @param delegate the new delegate
428      */
429     protected void setDelegate(FileConfigurationDelegate delegate)
430     {
431         this.delegate = delegate;
432     }
433 
434     /***
435      * A special implementation of the <code>FileConfiguration</code> interface that is
436      * used internally to implement the <code>FileConfiguration</code> methods
437      * for hierarchical configurations.
438      */
439     protected class FileConfigurationDelegate extends AbstractFileConfiguration
440     {
441         public void load(Reader in) throws ConfigurationException
442         {
443             AbstractHierarchicalFileConfiguration.this.load(in);
444         }
445 
446         public void save(Writer out) throws ConfigurationException
447         {
448             AbstractHierarchicalFileConfiguration.this.save(out);
449         }
450 
451         public void clear()
452         {
453             AbstractHierarchicalFileConfiguration.this.clear();
454         }
455     }
456 }