KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > util > text > LocalizedPropertiesLoader


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.tapestry.util.text;
16
17 import java.io.BufferedReader JavaDoc;
18 import java.io.IOException JavaDoc;
19 import java.io.InputStream JavaDoc;
20 import java.io.InputStreamReader JavaDoc;
21 import java.io.Reader JavaDoc;
22 import java.io.UnsupportedEncodingException JavaDoc;
23 import java.util.Map JavaDoc;
24
25 /**
26  * An object that loads a properties file from the provided input stream or reader.
27  * This class reads the property file exactly like java.util.Properties,
28  * except that it also allows the files to use an encoding other than ISO-8859-1
29  * and all non-ASCII characters are read correctly using the given encoding.
30  * In short, non-latin characters no longer need to be quoted using native2ascii.
31  *
32  * @author mb
33  * @since 4.0
34  */

35 public class LocalizedPropertiesLoader
36 {
37     private static final String JavaDoc HEX_DIGITS = "0123456789ABCDEF";
38     
39     private static final ICharacterMatcher WHITESPACE = new WhitespaceMatcher(false);
40     private static final ICharacterMatcher LINE_SEPARATOR = new AsciiCharacterMatcher("\n\r");
41     private static final ICharacterMatcher NOT_LINE_SEPARATOR = new InverseMatcher(LINE_SEPARATOR);
42     private static final ICharacterMatcher KEY_VALUE_SEPARATOR = new AsciiCharacterMatcher("=:");
43     private static final ICharacterMatcher SEPARATOR = new AsciiCharacterMatcher("=:\r\n");
44     private static final ICharacterMatcher COMMENT = new AsciiCharacterMatcher("#!");
45     private static final ICharacterMatcher WHITESPACE_OR_SEPARATOR =
46         new CompoundMatcher(new ICharacterMatcher[] { WHITESPACE, SEPARATOR });
47
48     private ExtendedReader _extendedReader;
49     
50     /**
51      * Creates a new loader that will load the properties from the given input stream
52      * using the default character encoding
53      *
54      * @param ins the input stream to load the properties from
55      */

56     public LocalizedPropertiesLoader(InputStream JavaDoc ins)
57     {
58         this(new InputStreamReader JavaDoc(ins));
59     }
60     
61     /**
62      * Creates a new loader that will load the properties from the given input stream
63      * using the provided character encoding
64      *
65      * @param ins the input stream to load the properties from
66      * @param encoding the character encoding the be used when reading from the stream
67      * @throws UnsupportedEncodingException if the name of the encoding cannot be recognized
68      */

69     public LocalizedPropertiesLoader(InputStream JavaDoc ins, String JavaDoc encoding) throws UnsupportedEncodingException JavaDoc
70     {
71         this(new InputStreamReader JavaDoc(ins, encoding));
72     }
73     
74     /**
75      * Creates a new loader that will load the properties from the given reader
76      *
77      * @param reader the Reader to load the properties from
78      */

79     public LocalizedPropertiesLoader(Reader JavaDoc reader)
80     {
81         _extendedReader = new ExtendedReader(new BufferedReader JavaDoc(reader));
82     }
83     
84     /**
85      * Read the properties from the provided stream and store them into the given map
86      *
87      * @param properties the map where the properties will be stored
88      * @throws IOException if an error occurs
89      */

90     public void load(Map JavaDoc properties) throws IOException JavaDoc
91     {
92         while (!isAtEndOfStream()) {
93             // we are at the beginning of a line.
94
// check whether it is a comment and if it is, skip it
95
int nextChar = _extendedReader.peek();
96             if (COMMENT.matches((char) nextChar)) {
97                 _extendedReader.skipCharacters(NOT_LINE_SEPARATOR);
98                 continue;
99             }
100             
101             _extendedReader.skipCharacters(WHITESPACE);
102             if (!isAtEndOfLine()) {
103                 // this line does not consist only of whitespace. the next word is the key
104
String JavaDoc key = readQuotedLine(WHITESPACE_OR_SEPARATOR);
105                 _extendedReader.skipCharacters(WHITESPACE);
106                 
107                 // if the next char is a key-value separator, read it and skip the following spaces
108
nextChar = _extendedReader.peek();
109                 if (nextChar > 0 && KEY_VALUE_SEPARATOR.matches((char) nextChar)) {
110                     _extendedReader.read();
111                     _extendedReader.skipCharacters(WHITESPACE);
112                 }
113
114                 // finally, read the value
115
String JavaDoc value = readQuotedLine(LINE_SEPARATOR);
116                 
117                 properties.put(key, value);
118             }
119             _extendedReader.skipCharacters(LINE_SEPARATOR);
120         }
121     }
122     
123     
124     private boolean isAtEndOfStream() throws IOException JavaDoc
125     {
126         int nextChar = _extendedReader.peek();
127         return (nextChar < 0);
128     }
129     
130     
131     private boolean isAtEndOfLine() throws IOException JavaDoc
132     {
133         int nextChar = _extendedReader.peek();
134         if (nextChar < 0)
135             return true;
136         return LINE_SEPARATOR.matches((char) nextChar);
137     }
138     
139     
140     private String JavaDoc readQuotedLine(ICharacterMatcher terminators) throws IOException JavaDoc
141     {
142         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
143         
144         while (true) {
145             // see what the next char is
146
int nextChar = _extendedReader.peek();
147             
148             // if at end of stream or the char is one of the terminators, stop
149
if (nextChar < 0 || terminators.matches((char) nextChar))
150                 break;
151
152             try {
153                 // read the char (and possibly unquote it)
154
char ch = readQuotedChar();
155                 buf.append(ch);
156             } catch (IgnoreCharacterException e) {
157                 // simply ignore -- no character was read
158
}
159         }
160         
161         return buf.toString();
162     }
163     
164
165     private char readQuotedChar() throws IOException JavaDoc, IgnoreCharacterException
166     {
167         int nextChar = _extendedReader.read();
168         if (nextChar < 0)
169             throw new IgnoreCharacterException();
170         char ch = (char) nextChar;
171         
172         // if the char is not the quotation char, simply return it
173
if (ch != '\\')
174             return ch;
175
176         // the character is a quotation character. unquote it
177
nextChar = _extendedReader.read();
178
179         // if at the end of the stream, stop
180
if (nextChar < 0)
181             throw new IgnoreCharacterException();
182         
183         ch = (char) nextChar;
184         switch (ch) {
185             case 'u' :
186                 char res = 0;
187                 for (int i = 0; i < 4; i++) {
188                     nextChar = _extendedReader.read();
189                     if (nextChar < 0)
190                         throw new IllegalArgumentException JavaDoc("Malformed \\uxxxx encoding.");
191                     char digitChar = (char) nextChar;
192                     int digit = HEX_DIGITS.indexOf(Character.toUpperCase(digitChar));
193                     if (digit < 0)
194                         throw new IllegalArgumentException JavaDoc("Malformed \\uxxxx encoding.");
195                     res = (char) (res * 16 + digit);
196                 }
197                 return res;
198
199             case '\r' :
200                 // if the next char is \n, read it and fall through
201
nextChar = _extendedReader.peek();
202                 if (nextChar == '\n')
203                     _extendedReader.read();
204             case '\n' :
205                 _extendedReader.skipCharacters(WHITESPACE);
206                 throw new IgnoreCharacterException();
207                 
208             case 't' : return '\t';
209             case 'n' : return '\n';
210             case 'r' : return '\r';
211             default: return ch;
212         }
213     }
214     
215
216     private static class IgnoreCharacterException extends Exception JavaDoc
217     {
218     }
219 }
220
Popular Tags