KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > configuration > AbstractFileConfiguration


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 JavaDoc;
20 import java.io.FileOutputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.InputStreamReader JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.io.OutputStreamWriter JavaDoc;
26 import java.io.Reader JavaDoc;
27 import java.io.UnsupportedEncodingException JavaDoc;
28 import java.io.Writer JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.util.Iterator JavaDoc;
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  * @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 JavaDoc fileName;
79
80     protected String JavaDoc basePath;
81
82     protected boolean autoSave;
83
84     protected ReloadingStrategy strategy;
85
86     private Object JavaDoc reloadLock = new Object JavaDoc();
87
88     private String JavaDoc encoding;
89
90     /**
91      * Default constructor
92      *
93      * @since 1.1
94      */

95     public AbstractFileConfiguration()
96     {
97         setReloadingStrategy(new InvariantReloadingStrategy());
98     }
99
100     /**
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      *
104      * @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 JavaDoc fileName) throws ConfigurationException
110     {
111         this();
112
113         // store the file name
114
setPath(fileName);
115
116         // load the file
117
load();
118     }
119
120     /**
121      * Creates and loads the configuration from the specified file.
122      *
123      * @param file The file to load.
124      * @throws ConfigurationException Error while loading the file
125      * @since 1.1
126      */

127     public AbstractFileConfiguration(File JavaDoc file) throws ConfigurationException
128     {
129         this();
130
131         // set the file and update the url, the base path and the file name
132
setFile(file);
133
134         // load the file
135
if (file.exists())
136         {
137             load();
138         }
139     }
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 JavaDoc url) throws ConfigurationException
149     {
150         this();
151
152         // set the URL and update the base path and the file name
153
setURL(url);
154
155         // load the file
156
load();
157     }
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         load(getFileName());
167     }
168
169     /**
170      * Locate the specified file and load the configuration.
171      *
172      * @param fileName the name of the file loaded
173      *
174      * @throws ConfigurationException
175      */

176     public void load(String JavaDoc fileName) throws ConfigurationException
177     {
178         try
179         {
180             URL JavaDoc url = ConfigurationUtils.locate(basePath, fileName);
181             if (url == null)
182             {
183                 throw new ConfigurationException("Cannot locate configuration source " + fileName);
184             }
185             load(url);
186         }
187         catch (ConfigurationException e)
188         {
189             throw e;
190         }
191         catch (Exception JavaDoc e)
192         {
193             throw new ConfigurationException(e.getMessage(), e);
194         }
195     }
196
197     /**
198      * Load the configuration from the specified file.
199      *
200      * @param file the loaded file
201      *
202      * @throws ConfigurationException
203      */

204     public void load(File JavaDoc file) throws ConfigurationException
205     {
206         try
207         {
208             load(file.toURL());
209         }
210         catch (ConfigurationException e)
211         {
212             throw e;
213         }
214         catch (Exception JavaDoc e)
215         {
216             throw new ConfigurationException(e.getMessage(), e);
217         }
218     }
219
220     /**
221      * 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 JavaDoc url) throws ConfigurationException
228     {
229         InputStream JavaDoc in = null;
230
231         try
232         {
233             in = url.openStream();
234             load(in);
235         }
236         catch (ConfigurationException e)
237         {
238             throw e;
239         }
240         catch (Exception JavaDoc e)
241         {
242             throw new ConfigurationException(e.getMessage(), e);
243         }
244         finally
245         {
246             // close the input stream
247
try
248             {
249                 if (in != null)
250                 {
251                     in.close();
252                 }
253             }
254             catch (IOException JavaDoc e)
255             {
256                 e.printStackTrace();
257             }
258         }
259     }
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 JavaDoc in) throws ConfigurationException
270     {
271         load(in, getEncoding());
272     }
273
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 JavaDoc in, String JavaDoc encoding) throws ConfigurationException
284     {
285         Reader JavaDoc reader = null;
286
287         if (encoding != null)
288         {
289             try
290             {
291                 reader = new InputStreamReader JavaDoc(in, encoding);
292             }
293             catch (UnsupportedEncodingException JavaDoc e)
294             {
295                 throw new ConfigurationException(
296                         "The requested encoding is not supported, try the default encoding.", e);
297             }
298         }
299
300         if (reader == null)
301         {
302             reader = new InputStreamReader JavaDoc(in);
303         }
304
305         load(reader);
306     }
307
308     /**
309      * Save the configuration.
310      *
311      * @throws ConfigurationException
312      */

313     public void save() throws ConfigurationException
314     {
315         save(fileName);
316         strategy.init();
317     }
318
319     /**
320      * Save the configuration to the specified file. This doesn't change the
321      * source of the configuration, use setFileName() if you need it.
322      *
323      * @param fileName
324      *
325      * @throws ConfigurationException
326      */

327     public void save(String JavaDoc fileName) throws ConfigurationException
328     {
329         try
330         {
331             File JavaDoc file = ConfigurationUtils.getFile(basePath, fileName);
332             if (file == null)
333             {
334                 throw new ConfigurationException("Invalid file name for save: " + fileName);
335             }
336             save(file);
337         }
338         catch (ConfigurationException e)
339         {
340             throw e;
341         }
342         catch (Exception JavaDoc e)
343         {
344             throw new ConfigurationException(e.getMessage(), e);
345         }
346     }
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      *
353      * @param url
354      *
355      * @throws ConfigurationException
356      */

357     public void save(URL JavaDoc url) throws ConfigurationException
358     {
359         File JavaDoc file = ConfigurationUtils.fileFromURL(url);
360         if (file != null)
361         {
362             save(file);
363         }
364         else
365         {
366             throw new ConfigurationException("Could not save to URL " + url);
367         }
368     }
369
370     /**
371      * Save the configuration to the specified file. The file is created
372      * automatically if it doesn't exist. This doesn't change the source
373      * of the configuration, use {@link #setFile} if you need it.
374      *
375      * @param file
376      *
377      * @throws ConfigurationException
378      */

379     public void save(File JavaDoc file) throws ConfigurationException
380     {
381         OutputStream JavaDoc out = null;
382
383         try
384         {
385             // create the file if necessary
386
createPath(file);
387             out = new FileOutputStream JavaDoc(file);
388             save(out);
389         }
390         catch (IOException JavaDoc e)
391         {
392             throw new ConfigurationException(e.getMessage(), e);
393         }
394         finally
395         {
396             // close the output stream
397
try
398             {
399                 if (out != null)
400                 {
401                     out.close();
402                 }
403             }
404             catch (IOException JavaDoc e)
405             {
406                 e.printStackTrace();
407             }
408         }
409     }
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 JavaDoc out) throws ConfigurationException
420     {
421         save(out, getEncoding());
422     }
423
424     /**
425      * Save the configuration to the specified stream, using the specified
426      * encoding. If the encoding is null the default encoding is used.
427      *
428      * @param out
429      * @param encoding
430      * @throws ConfigurationException
431      */

432     public void save(OutputStream JavaDoc out, String JavaDoc encoding) throws ConfigurationException
433     {
434         Writer JavaDoc writer = null;
435
436         if (encoding != null)
437         {
438             try
439             {
440                 writer = new OutputStreamWriter JavaDoc(out, encoding);
441             }
442             catch (UnsupportedEncodingException JavaDoc e)
443             {
444                 throw new ConfigurationException(
445                         "The requested encoding is not supported, try the default encoding.", e);
446             }
447         }
448
449         if (writer == null)
450         {
451             writer = new OutputStreamWriter JavaDoc(out);
452         }
453
454         save(writer);
455     }
456
457     /**
458      * Return the name of the file.
459      */

460     public String JavaDoc getFileName()
461     {
462         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      * setPath()}</code> to set a full qualified file name.
469      *
470      * @param fileName the name of the file
471      */

472     public void setFileName(String JavaDoc fileName)
473     {
474         this.fileName = fileName;
475     }
476
477     /**
478      * Return the base path.
479      */

480     public String JavaDoc getBasePath()
481     {
482         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     public void setBasePath(String JavaDoc basePath)
492     {
493         this.basePath = basePath;
494     }
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     public File JavaDoc getFile()
504     {
505         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 JavaDoc file)
516     {
517         setFileName(file.getName());
518         setBasePath((file.getParentFile() != null) ? file.getParentFile().getAbsolutePath() : null);
519     }
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      */

528     public String JavaDoc getPath()
529     {
530         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      * @param path the full path name of the configuration file
538      */

539     public void setPath(String JavaDoc path)
540     {
541         setFile(new File JavaDoc(path));
542     }
543
544     /**
545      * Return the URL where the configuration is stored.
546      *
547      * @return the configuration's location as URL
548      */

549     public URL JavaDoc getURL()
550     {
551         return ConfigurationUtils.locate(getBasePath(), getFileName());
552     }
553
554     /**
555      * Set the location of this configuration as a URL. For loading this can be
556      * an arbitrary URL with a supported protocol. If the configuration is to
557      * 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 JavaDoc url)
563     {
564         setBasePath(ConfigurationUtils.getBasePath(url));
565         setFileName(ConfigurationUtils.getFileName(url));
566     }
567
568     public void setAutoSave(boolean autoSave)
569     {
570         this.autoSave = autoSave;
571     }
572
573     public boolean isAutoSave()
574     {
575         return autoSave;
576     }
577
578     /**
579      * Save the configuration if the automatic persistence is enabled
580      * and if a file is specified.
581      */

582     protected void possiblySave()
583     {
584         if (autoSave && fileName != null)
585         {
586             try
587             {
588                 save();
589             }
590             catch (ConfigurationException e)
591             {
592                 throw new ConfigurationRuntimeException("Failed to auto-save", e);
593             }
594         }
595     }
596
597     protected void addPropertyDirect(String JavaDoc key, Object JavaDoc obj)
598     {
599         super.addPropertyDirect(key, obj);
600         possiblySave();
601     }
602
603     public void clearProperty(String JavaDoc key)
604     {
605         super.clearProperty(key);
606         possiblySave();
607     }
608
609     public ReloadingStrategy getReloadingStrategy()
610     {
611         return strategy;
612     }
613
614     public void setReloadingStrategy(ReloadingStrategy strategy)
615     {
616         this.strategy = strategy;
617         strategy.setConfiguration(this);
618         strategy.init();
619     }
620
621     public void reload()
622     {
623         synchronized (reloadLock)
624         {
625             if (strategy.reloadingRequired())
626             {
627                 try
628                 {
629                     clear();
630                     load();
631
632                     // notify the strategy
633
strategy.reloadingPerformed();
634                 }
635                 catch (Exception JavaDoc e)
636                 {
637                     e.printStackTrace();
638                     // todo rollback the changes if the file can't be reloaded
639
}
640             }
641         }
642     }
643
644     public Object JavaDoc getProperty(String JavaDoc key)
645     {
646         reload();
647         return super.getProperty(key);
648     }
649
650     public boolean isEmpty()
651     {
652         reload();
653         return super.isEmpty();
654     }
655
656     public boolean containsKey(String JavaDoc key)
657     {
658         reload();
659         return super.containsKey(key);
660     }
661
662     public Iterator JavaDoc getKeys()
663     {
664         reload();
665         return super.getKeys();
666     }
667
668     /**
669      * Create the path to the specified file.
670      */

671     private void createPath(File JavaDoc file)
672     {
673         if (file != null)
674         {
675             // create the path to the file if the file doesn't exist
676
if (!file.exists())
677             {
678                 File JavaDoc parent = file.getParentFile();
679                 if (parent != null && !parent.exists())
680                 {
681                     parent.mkdirs();
682                 }
683             }
684         }
685     }
686
687     public String JavaDoc getEncoding()
688     {
689         return encoding;
690     }
691
692     public void setEncoding(String JavaDoc encoding)
693     {
694         this.encoding = encoding;
695     }
696 }
Popular Tags