KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > myvietnam > mvncore > configuration > BasePropertiesConfiguration


1 package net.myvietnam.mvncore.configuration;
2
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if
22  * any, must include the following acknowledgement:
23  * "This product includes software developed by the
24  * Apache Software Foundation (http://www.apache.org/)."
25  * Alternately, this acknowledgement may appear in the software itself,
26  * if and wherever such third-party acknowledgements normally appear.
27  *
28  * 4. The names "The Jakarta Project", "Commons", and "Apache Software
29  * Foundation" must not be used to endorse or promote products derived
30  * from this software without prior written permission. For written
31  * permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache"
34  * nor may "Apache" appear in their names without prior written
35  * permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation. For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  */

56
57 import java.io.File JavaDoc;
58 import java.io.FileWriter JavaDoc;
59 import java.io.IOException JavaDoc;
60 import java.io.InputStream JavaDoc;
61 import java.io.InputStreamReader JavaDoc;
62 import java.io.LineNumberReader JavaDoc;
63 import java.io.Reader JavaDoc;
64 import java.io.UnsupportedEncodingException JavaDoc;
65
66 import java.util.Date JavaDoc;
67 import java.util.Iterator JavaDoc;
68
69 import org.apache.commons.lang.StringUtils;
70
71 /**
72  * loads the configuration from a properties file. <p>
73  *
74  * <p>The properties file syntax is explained here:
75  *
76  * <ul>
77  * <li>
78  * Each property has the syntax <code>key = value</code>
79  * </li>
80  * <li>
81  * The <i>key</i> may use any character but the equal sign '='.
82  * </li>
83  * <li>
84  * <i>value</i> may be separated on different lines if a backslash
85  * is placed at the end of the line that continues below.
86  * </li>
87  * <li>
88  * If <i>value</i> is a list of strings, each token is separated
89  * by a comma ','.
90  * </li>
91  * <li>
92  * Commas in each token are escaped placing a backslash right before
93  * the comma.
94  * </li>
95  * <li>
96  * If a <i>key</i> is used more than once, the values are appended
97  * like if they were on the same line separated with commas.
98  * </li>
99  * <li>
100  * Blank lines and lines starting with character '#' are skipped.
101  * </li>
102  * <li>
103  * If a property is named "include" (or whatever is defined by
104  * setInclude() and getInclude() and the value of that property is
105  * the full path to a file on disk, that file will be included into
106  * the ConfigurationsRepository. You can also pull in files relative
107  * to the parent configuration file. So if you have something
108  * like the following:
109  *
110  * include = additional.properties
111  *
112  * Then "additional.properties" is expected to be in the same
113  * directory as the parent configuration file.
114  *
115  * Duplicate name values will be replaced, so be careful.
116  *
117  * </li>
118  * </ul>
119  *
120  * <p>Here is an example of a valid extended properties file:
121  *
122  * <p><pre>
123  * # lines starting with # are comments
124  *
125  * # This is the simplest property
126  * key = value
127  *
128  * # A long property may be separated on multiple lines
129  * longvalue = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
130  * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
131  *
132  * # This is a property with many tokens
133  * tokens_on_a_line = first token, second token
134  *
135  * # This sequence generates exactly the same result
136  * tokens_on_multiple_lines = first token
137  * tokens_on_multiple_lines = second token
138  *
139  * # commas may be escaped in tokens
140  * commas.excaped = Hi\, what'up?
141  *
142  * # properties can reference other properties
143  * base.prop = /base
144  * first.prop = ${base.prop}/first
145  * second.prop = ${first.prop}/second
146  * </pre>
147  *
148  * @author <a HREF="mailto:stefano@apache.org">Stefano Mazzocchi</a>
149  * @author <a HREF="mailto:jon@latchkey.com">Jon S. Stevens</a>
150  * @author <a HREF="mailto:daveb@miceda-data">Dave Bryson</a>
151  * @author <a HREF="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
152  * @author <a HREF="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
153  * @author <a HREF="mailto:kjohnson@transparent.com">Kent Johnson</a>
154  * @author <a HREF="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
155  * @author <a HREF="mailto:ipriha@surfeu.fi">Ilkka Priha</a>
156  * @author <a HREF="mailto:jvanzyl@apache.org">Jason van Zyl</a>
157  * @author <a HREF="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
158  * @author <a HREF="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
159  * @version $Id: BasePropertiesConfiguration.java,v 1.2 2003/12/10 04:30:45 minhnn Exp $
160  */

161 public abstract class BasePropertiesConfiguration
162     extends BasePathConfiguration
163 {
164     /** Allow file inclusion or not */
165     private boolean includesAllowed = false;
166
167     /**
168      * This is the name of the property that can point to other
169      * properties file for including other properties files.
170      */

171     protected static String JavaDoc include = "include";
172
173     /**
174      * Implementations of this class must implement this method.
175      *
176      * @param resourceName The Resource to load
177      * @return An Input Stream
178      *
179      * @throws IOException Error while loading the properties file
180      */

181     protected abstract InputStream JavaDoc getPropertyStream(String JavaDoc resourceName)
182         throws IOException JavaDoc;
183
184     /**
185      * Load the properties from the given input stream.
186      *
187      * @param input An InputStream.
188      * @throws IOException
189      */

190     public void load(InputStream JavaDoc input)
191         throws IOException JavaDoc
192     {
193         load(input, null);
194     }
195
196     /**
197      * Load the properties from the given input stream and using the specified
198      * encoding.
199      *
200      * @param input An InputStream.
201      * @param enc An encoding.
202      * @exception IOException
203      */

204     public synchronized void load(InputStream JavaDoc input, String JavaDoc enc)
205         throws IOException JavaDoc
206     {
207         PropertiesReader reader = null;
208         if (enc != null)
209         {
210             try
211             {
212                 reader =
213                   new PropertiesReader(new InputStreamReader JavaDoc(input, enc));
214             }
215             catch (UnsupportedEncodingException JavaDoc e)
216             {
217                 // Get one with the default encoding...
218
}
219         }
220
221         if (reader == null)
222         {
223             reader = new PropertiesReader(new InputStreamReader JavaDoc(input));
224         }
225
226         while (true)
227         {
228             String JavaDoc line = reader.readProperty();
229
230             if (line == null)
231             {
232                 break; // EOF
233
}
234
235             int equalSign = line.indexOf('=');
236             if (equalSign > 0)
237             {
238                 String JavaDoc key = line.substring(0, equalSign).trim();
239                 String JavaDoc value = line.substring(equalSign + 1).trim();
240
241                 // Though some software (e.g. autoconf) may produce
242
// empty values like foo=\n, emulate the behavior of
243
// java.util.Properties by setting the value to the
244
// empty string.
245

246                 if (StringUtils.isNotEmpty(getInclude())
247                     && key.equalsIgnoreCase(getInclude()))
248                 {
249                     if (getIncludesAllowed())
250                     {
251                         String JavaDoc [] files = StringUtils.split(value, ",");
252                         for (int cnt = 0 ; cnt < files.length ; cnt++)
253                         {
254                             load(getPropertyStream(files[cnt].trim()));
255                         }
256                     }
257                 }
258                 else
259                 {
260                     addProperty(key, value);
261                 }
262             }
263         }
264     }
265
266     /**
267      * save properties to a file.
268      * properties with multiple values are saved comma seperated.
269      *
270      * @param filename name of the properties file
271      * @throws IOException
272      */

273     public void save(String JavaDoc filename)
274         throws IOException JavaDoc
275     {
276         File JavaDoc file = new File JavaDoc(filename);
277         PropertiesWriter out = new PropertiesWriter(file);
278
279         out.writeComment("written by PropertiesConfiguration");
280         out.writeComment(new Date JavaDoc().toString());
281
282         for (Iterator JavaDoc i = this.getKeys(); i.hasNext();)
283         {
284             String JavaDoc key = (String JavaDoc) i.next();
285             String JavaDoc value = StringUtils.join(this.getStringArray(key), ", ");
286             out.writeProperty(key, value);
287         }
288         out.flush();
289         out.close();
290     }
291
292     /**
293      * Gets the property value for including other properties files.
294      * By default it is "include".
295      *
296      * @return A String.
297      */

298     public String JavaDoc getInclude()
299     {
300         return BasePropertiesConfiguration.include;
301     }
302
303     /**
304      * Sets the property value for including other properties files.
305      * By default it is "include".
306      *
307      * @param inc A String.
308      */

309     public void setInclude(String JavaDoc inc)
310     {
311         BasePropertiesConfiguration.include = inc;
312     }
313
314     /**
315      * Controls whether additional files can be loaded by the include = <xxx>
316      * statement or not. Base rule is, that objects created by the empty
317      * C'tor can not have included files.
318      *
319      * @param includesAllowed includesAllowed True if Includes are allowed.
320      */

321     protected void setIncludesAllowed(boolean includesAllowed)
322     {
323         this.includesAllowed = includesAllowed;
324     }
325
326     /**
327      * Reports the status of file inclusion.
328      *
329      * @return True if include files are loaded.
330      */

331     public boolean getIncludesAllowed()
332     {
333         return this.includesAllowed;
334     }
335
336     /**
337      * This class is used to read properties lines. These lines do
338      * not terminate with new-line chars but rather when there is no
339      * backslash sign a the end of the line. This is used to
340      * concatenate multiple lines for readability.
341      */

342     class PropertiesReader
343         extends LineNumberReader JavaDoc
344     {
345         /**
346          * Constructor.
347          *
348          * @param reader A Reader.
349          */

350         public PropertiesReader(Reader JavaDoc reader)
351         {
352             super(reader);
353         }
354
355         /**
356          * Read a property. Returns null if Stream is
357          * at EOF. Concatenates lines ending with "\".
358          * Skips lines beginning with "#" and empty lines.
359          *
360          * @return A string containing a property value or null
361          *
362          * @exception IOException
363          */

364         public String JavaDoc readProperty()
365             throws IOException JavaDoc
366         {
367             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
368
369             while (true)
370             {
371                 String JavaDoc line = readLine();
372                 if (line == null)
373                 {
374                     // EOF
375
return null;
376                 }
377
378                 line = line.trim();
379
380                 if (StringUtils.isEmpty(line)
381                     || (line.charAt(0) == '#'))
382                 {
383                     continue;
384                 }
385
386                 if (line.endsWith("\\"))
387                 {
388                     line = line.substring(0, line.length() - 1);
389                     buffer.append(line);
390                 }
391                 else
392                 {
393                     buffer.append(line);
394                     break;
395                 }
396             }
397             return buffer.toString();
398         }
399     } // class PropertiesReader
400

401     /**
402      * This class is used to write properties lines.
403      */

404     class PropertiesWriter
405         extends FileWriter JavaDoc
406     {
407         /**
408          * Constructor.
409          *
410          * @param file the proerties file
411          * @throws IOException
412          */

413         public PropertiesWriter(File JavaDoc file)
414             throws IOException JavaDoc
415         {
416             super(file);
417         }
418
419         /**
420          * Write a property.
421          *
422          * @param key
423          * @param value
424          * @exception IOException
425          */

426         public void writeProperty(String JavaDoc key, String JavaDoc value)
427             throws IOException JavaDoc
428         {
429             write(key);
430             write(" = ");
431             write(value != null ? value : "");
432             write('\n');
433         }
434
435         /**
436          * Write a comment.
437          *
438          * @param comment
439          * @exception IOException
440          */

441         public void writeComment(String JavaDoc comment)
442             throws IOException JavaDoc
443         {
444             write("# " + comment + "\n");
445         }
446     } // class PropertiesWriter
447
}
448
Popular Tags