Commit | Line | Data |
---|---|---|
2a96e7b2 NR |
1 | package be.nikiroo.jvcard.resources; |
2 | ||
e119a1c1 NR |
3 | import java.io.BufferedWriter; |
4 | import java.io.File; | |
5 | import java.io.FileOutputStream; | |
6 | import java.io.IOException; | |
7 | import java.io.OutputStreamWriter; | |
8 | import java.io.Writer; | |
9 | import java.lang.reflect.Field; | |
2a96e7b2 NR |
10 | import java.util.Locale; |
11 | import java.util.ResourceBundle; | |
12 | ||
13 | /** | |
14 | * This class help you get UTF-8 bundles for this application. | |
15 | * | |
16 | * @author niki | |
17 | * | |
18 | */ | |
19 | public class Bundles { | |
e27d1404 NR |
20 | /** |
21 | * The configuration directory where we try to get the <tt>.properties</tt> | |
22 | * in priority, or NULL to get the information from the compiled resources. | |
23 | */ | |
7f82bf68 NR |
24 | static private String confDir = getConfDir(); |
25 | ||
2a96e7b2 | 26 | /** |
e119a1c1 NR |
27 | * The type of configuration information the associated {@link Bundle} will |
28 | * convey. | |
2a96e7b2 | 29 | * |
e119a1c1 NR |
30 | * @author niki |
31 | * | |
2a96e7b2 | 32 | */ |
e119a1c1 NR |
33 | public enum Target { |
34 | colors, display, jvcard, remote, resources | |
2a96e7b2 NR |
35 | } |
36 | ||
37 | /** | |
e119a1c1 NR |
38 | * Return the configuration directory where to try to find the |
39 | * <tt>.properties</tt> files in priority. | |
2a96e7b2 | 40 | * |
e119a1c1 | 41 | * @return the configuration directory |
2a96e7b2 | 42 | */ |
e119a1c1 NR |
43 | static private String getConfDir() { |
44 | // Do not override user-supplied config directory (see --help) | |
45 | if (Bundles.confDir != null) | |
46 | return Bundles.confDir; | |
47 | ||
48 | try { | |
49 | ResourceBundle bundle = ResourceBundle.getBundle(Bundles.class | |
50 | .getPackage().getName() + "." + "jvcard", | |
51 | Locale.getDefault(), new FixedResourceBundleControl(null)); | |
52 | ||
53 | String configDir = bundle.getString("CONFIG_DIR"); | |
54 | if (configDir != null && configDir.trim().length() > 0) | |
55 | return configDir; | |
56 | } catch (Exception e) { | |
57 | } | |
58 | ||
59 | return null; | |
2a96e7b2 | 60 | } |
7f82bf68 NR |
61 | |
62 | /** | |
63 | * Set the primary configuration directory to look for <tt>.properties</tt> | |
64 | * files in. | |
65 | * | |
66 | * All {@link ResourceBundle}s returned by this class after that point will | |
67 | * respect this new directory. | |
68 | * | |
69 | * @param confDir | |
70 | * the new directory | |
71 | */ | |
72 | static public void setDirectory(String confDir) { | |
73 | Bundles.confDir = confDir; | |
74 | } | |
75 | ||
e27d1404 NR |
76 | /** |
77 | * Get the primary configuration directory to look for <tt>.properties</tt> | |
78 | * files in. | |
79 | * | |
80 | * @return the directory | |
81 | */ | |
82 | static public String getDirectory() { | |
83 | return Bundles.confDir; | |
84 | } | |
85 | ||
7f82bf68 | 86 | /** |
e119a1c1 NR |
87 | * This class encapsulate a {@link ResourceBundle} in UTF-8. It only allows |
88 | * to retrieve values associated to an enumeration, and allows some | |
89 | * additional methods. | |
7f82bf68 | 90 | * |
e119a1c1 NR |
91 | * @author niki |
92 | * | |
93 | * @param <E> | |
94 | * the enum to use to get values out of this class | |
7f82bf68 | 95 | */ |
e119a1c1 NR |
96 | public class Bundle<E extends Enum<E>> { |
97 | private Class<E> type; | |
98 | protected Target name; | |
99 | protected ResourceBundle map; | |
7f82bf68 | 100 | |
e119a1c1 NR |
101 | /** |
102 | * Create a new {@link Bundles} of the given name. | |
103 | * | |
104 | * @param type | |
105 | * a runtime instance of the class of E | |
106 | * | |
107 | * @param name | |
108 | * the name of the {@link Bundles} | |
109 | */ | |
110 | protected Bundle(Class<E> type, Target name) { | |
111 | this.type = type; | |
112 | this.name = name; | |
113 | this.map = getBundle(name); | |
114 | } | |
7f82bf68 | 115 | |
e119a1c1 NR |
116 | /** |
117 | * Return the value associated to the given id as a {@link String}. | |
118 | * | |
119 | * @param mame | |
120 | * the id of the value to get | |
121 | * | |
122 | * @return the associated value | |
123 | */ | |
124 | public String getString(E id) { | |
125 | if (map.containsKey(id.name())) { | |
126 | return map.getString(id.name()).trim(); | |
127 | } | |
128 | ||
129 | return ""; | |
7f82bf68 NR |
130 | } |
131 | ||
e119a1c1 NR |
132 | /** |
133 | * Return the value associated to the given id as a {@link Boolean}. | |
134 | * | |
135 | * @param mame | |
136 | * the id of the value to get | |
137 | * | |
138 | * @return the associated value | |
139 | */ | |
140 | public Boolean getBoolean(E id) { | |
141 | String str = getString(id); | |
142 | if (str != null && str.length() > 0) { | |
143 | if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("on") | |
144 | || str.equalsIgnoreCase("yes")) | |
145 | return true; | |
146 | if (str.equalsIgnoreCase("false") | |
147 | || str.equalsIgnoreCase("off") | |
148 | || str.equalsIgnoreCase("no")) | |
149 | return false; | |
150 | ||
151 | } | |
152 | ||
153 | return null; | |
154 | } | |
155 | ||
156 | /** | |
157 | * Return the value associated to the given id as a {@link boolean}. | |
158 | * | |
159 | * @param mame | |
160 | * the id of the value to get | |
161 | * @param def | |
162 | * the default value when it is not present in the config | |
163 | * file or if it is not a boolean value | |
164 | * | |
165 | * @return the associated value | |
166 | */ | |
167 | public boolean getBoolean(E id, boolean def) { | |
168 | Boolean b = getBoolean(id); | |
169 | if (b != null) | |
170 | return b; | |
171 | ||
172 | return def; | |
173 | } | |
174 | ||
175 | /** | |
176 | * Return the value associated to the given id as an {@link Integer}. | |
177 | * | |
178 | * @param mame | |
179 | * the id of the value to get | |
180 | * | |
181 | * @return the associated value | |
182 | */ | |
183 | public Integer getInteger(E id) { | |
184 | try { | |
185 | return Integer.parseInt(getString(id)); | |
186 | } catch (Exception e) { | |
187 | } | |
188 | ||
189 | return null; | |
190 | } | |
191 | ||
192 | /** | |
193 | * Return the value associated to the given id as a {@link int}. | |
194 | * | |
195 | * @param mame | |
196 | * the id of the value to get | |
197 | * @param def | |
198 | * the default value when it is not present in the config | |
199 | * file or if it is not a int value | |
200 | * | |
201 | * @return the associated value | |
202 | */ | |
203 | public int getInteger(E id, int def) { | |
204 | Integer i = getInteger(id); | |
205 | if (i != null) | |
206 | return i; | |
207 | ||
208 | return def; | |
209 | } | |
210 | ||
211 | /** | |
212 | * Create/update the .properties file. Will use the most likely | |
213 | * candidate as base if the file does not already exists and this | |
214 | * resource is translatable (for instance, "en_US" will use "en" as a | |
215 | * base if the resource is a translation file). | |
216 | * | |
217 | * @param path | |
218 | * the path where the .properties files are | |
219 | * | |
220 | * @throws IOException | |
221 | * in case of IO errors | |
222 | */ | |
223 | public void updateFile(String path) throws IOException { | |
224 | File file = getUpdateFile(path); | |
225 | ||
226 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( | |
227 | new FileOutputStream(file), "UTF-8")); | |
228 | ||
229 | writeHeader(writer); | |
230 | writer.write("\n"); | |
231 | writer.write("\n"); | |
232 | ||
233 | for (Field field : type.getDeclaredFields()) { | |
234 | Meta meta = field.getAnnotation(Meta.class); | |
235 | if (meta != null) { | |
236 | E id = E.valueOf(type, field.getName()); | |
237 | String info = getMetaInfo(meta); | |
238 | ||
239 | if (info != null) { | |
240 | writer.write(info); | |
241 | writer.write("\n"); | |
242 | } | |
243 | ||
244 | writeValue(writer, id); | |
245 | } | |
246 | } | |
247 | ||
248 | writer.close(); | |
249 | } | |
7f82bf68 | 250 | |
e119a1c1 NR |
251 | /** |
252 | * Return formated, display-able information from the {@link Meta} field | |
253 | * given. Each line will always starts with a "#" character. | |
254 | * | |
255 | * @param meta | |
256 | * the {@link Meta} field | |
257 | * | |
258 | * @return the information to display or NULL if none | |
259 | */ | |
260 | protected String getMetaInfo(Meta meta) { | |
261 | String what = meta.what(); | |
262 | String where = meta.where(); | |
263 | String format = meta.format(); | |
264 | String info = meta.info(); | |
265 | ||
266 | int opt = what.length() + where.length() + format.length(); | |
267 | if (opt + info.length() == 0) | |
268 | return null; | |
269 | ||
270 | StringBuilder builder = new StringBuilder(); | |
271 | builder.append("# "); | |
272 | ||
273 | if (opt > 0) { | |
274 | builder.append("("); | |
275 | if (what.length() > 0) { | |
276 | builder.append("WHAT: " + what); | |
277 | if (where.length() + format.length() > 0) | |
278 | builder.append(", "); | |
279 | } | |
280 | ||
281 | if (where.length() > 0) { | |
282 | builder.append("WHERE: " + where); | |
283 | if (format.length() > 0) | |
284 | builder.append(", "); | |
285 | } | |
286 | ||
287 | if (format.length() > 0) { | |
288 | builder.append("FORMAT: " + format); | |
289 | } | |
290 | ||
291 | builder.append(")"); | |
292 | if (info.length() > 0) { | |
293 | builder.append("\n# "); | |
294 | } | |
295 | } | |
296 | ||
297 | builder.append(info); | |
298 | ||
299 | return builder.toString(); | |
300 | } | |
301 | ||
302 | /** | |
303 | * Write the header found in the configuration <tt>.properties</tt> file | |
304 | * of this {@link Bundles}. | |
305 | * | |
306 | * @param writer | |
307 | * the {@link Writer} to write the header in | |
308 | * | |
309 | * @throws IOException | |
310 | * in case of IO error | |
311 | */ | |
312 | protected void writeHeader(Writer writer) throws IOException { | |
313 | writer.write("# " + name + "\n"); | |
314 | writer.write("#\n"); | |
315 | } | |
316 | ||
317 | /** | |
318 | * Write the given id to the config file, i.e., | |
319 | * "MY_ID = my_curent_value" followed by a new line | |
320 | * | |
321 | * @param writer | |
322 | * the {@link Writer} to write into | |
323 | * @param id | |
324 | * the id to write | |
325 | * | |
326 | * @throws IOException | |
327 | * in case of IO error | |
328 | */ | |
329 | protected void writeValue(Writer writer, E id) throws IOException { | |
47d06cf3 NR |
330 | writeValue(writer, id.name(), getString(id)); |
331 | } | |
332 | ||
333 | /** | |
334 | * Write the given data to the config file, i.e., | |
335 | * "MY_ID = my_curent_value" followed by a new line | |
336 | * | |
337 | * @param writer | |
338 | * the {@link Writer} to write into | |
339 | * @param id | |
340 | * the id to write | |
341 | * @param value | |
342 | * the id's value | |
343 | * | |
344 | * @throws IOException | |
345 | * in case of IO error | |
346 | */ | |
347 | protected void writeValue(Writer writer, String id, String value) | |
348 | throws IOException { | |
349 | writer.write(id); | |
e119a1c1 | 350 | writer.write(" = "); |
88eb8122 | 351 | |
47d06cf3 | 352 | String[] lines = value.replaceAll("\\\t", "\\\\\\t").split("\n"); |
88eb8122 NR |
353 | for (int i = 0; i < lines.length; i++) { |
354 | writer.write(lines[i]); | |
355 | if (i < lines.length - 1) { | |
356 | writer.write("\\n\\"); | |
357 | } | |
358 | writer.write("\n"); | |
359 | } | |
e119a1c1 NR |
360 | } |
361 | ||
362 | /** | |
363 | * Return the non-localised bundle of the given name. | |
364 | * | |
365 | * @param name | |
366 | * the name of the bundle to load | |
367 | * | |
368 | * @return the bundle | |
369 | */ | |
370 | protected ResourceBundle getBundle(Target name) { | |
371 | return ResourceBundle.getBundle(Bundles.class.getPackage() | |
372 | .getName() + "." + name.name(), | |
373 | new FixedResourceBundleControl(confDir)); | |
374 | } | |
375 | ||
376 | /** | |
377 | * Return the localised bundle of the given name and {@link Locale}. | |
378 | * | |
379 | * @param name | |
380 | * the name of the bundle to load | |
381 | * @param locale | |
382 | * the {@link Locale} to use | |
383 | * | |
384 | * @return the localised bundle | |
385 | */ | |
386 | protected ResourceBundle getBundle(Target name, Locale locale) { | |
387 | return ResourceBundle.getBundle(Bundles.class.getPackage() | |
388 | .getName() + "." + name.name(), locale, | |
389 | new FixedResourceBundleControl(confDir)); | |
390 | } | |
391 | ||
392 | /** | |
393 | * Return the source file for this {@link Bundles} from the given path. | |
394 | * | |
395 | * @param path | |
396 | * the path where the .properties files are | |
397 | * | |
398 | * @return the source {@link File} | |
399 | * | |
400 | * @throws IOException | |
401 | * in case of IO errors | |
402 | */ | |
403 | protected File getUpdateFile(String path) { | |
404 | return new File(path, name.name() + ".properties"); | |
405 | } | |
406 | } | |
2a96e7b2 | 407 | } |