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