Source code: org/dinopolis/util/resource/FileResources.java
1 /***********************************************************************
2 * @(#)$RCSfile: FileResources.java,v $ $Revision: 1.7 $ $Date: 2003/11/18 11:34:08 $
3 *
4 * Copyright (c) 2001 IICM, Graz University of Technology
5 * Inffeldgasse 16c, A-8010 Graz, Austria.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License (LGPL)
9 * as published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ***********************************************************************/
22
23
24 package org.dinopolis.util.resource;
25
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.FileNotFoundException;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.net.MalformedURLException;
32 import java.net.URL;
33 import java.util.Enumeration;
34 import java.util.HashSet;
35 import java.util.Locale;
36 import java.util.MissingResourceException;
37 import java.util.Properties;
38 import java.util.ResourceBundle;
39 import java.util.Vector;
40 import java.util.WeakHashMap;
41
42 //----------------------------------------------------------------------
43 /**
44 * This class provides the functionality to read resources from a
45 * system or user resource file. The way that this is done is: It
46 * looks for a resource file within the users home directory and if a
47 * proper file is found, it looks for the specific proporty. If no
48 * file or the specific property was not found, the system resource
49 * file is being asked for the property.<p>
50 *
51 * Stored resources can not only be requested as <code>Strings</code>,
52 * but also in many different other types, like <code>integers</code>,
53 * <code>StringArrays</code>, <code>booleans</code>, <code>Colors</code>,
54 * <code>Icons</code> and others.<p>
55 *
56 * Resource files contain key/value pairs. The keys uniquely
57 * identify a locale-specific object in the bundle. Here's an
58 * example resource file that contains two key/value pairs:
59 * <blockquote>
60 * <pre>
61 * my_app.dimension.width=300
62 * my_app.dimension.height=200
63 * </pre>
64 * </blockquote>
65 *
66 * Keys are always <code>String</code>s.
67 * In this example, the keys are <code>my_app.dimension.width</code>
68 * and <code>my_app.dimension.height</code>.
69 *
70 * In the above example, the values
71 * are also <code>String</code>s--<code>200</code> and <code>300</code>--but
72 * they may also be interpreted as integer values using the method
73 * {@link #getInt}.<p>
74 *
75 * The single argumented getter methods all require the key as an
76 * argument and return the object if found. If the object is not
77 * found, the getter method throws a
78 * <code>MissingResourceException</code>. To avoid this behavior, it
79 * is also possible to use the corresponding methods that take two
80 * arguments, the key and the default value. If no property was bound
81 * under the given key, the default value will be returned instead of
82 * throwing a <code>MissingResourceException</code>.
83 *
84 * @author Dieter Freismuth
85 * @version $Revision: 1.7 $
86 */
87
88 public class FileResources extends AbstractResources
89 {
90 /** the property filename extension */
91 protected final static String PROPERTY_EXTENSION = ".properties";
92
93 /** the title suffix */
94 protected final static String TITLE_SUFFIX = ".title";
95
96 /** the description suffix */
97 protected final static String DESCRIPTION_SUFFIX = ".description";
98
99 /** the possible values suffix */
100 protected final static String POSSIBLE_VALUES_SUFFIX = ".possible_values";
101
102 /** the type suffix */
103 protected final static String TYPE_SUFFIX = ".type";
104
105 /** key - value seperators */
106 protected static final String KEY_VALUE_SEPARATORS = "=: \t\r\n\f";
107
108 /** whitespace charakters */
109 protected final static String WHITE_SPACE_CHARS = " \t\r\n\f";
110
111 /** the resource bundle */
112 protected ResourceBundle system_bundle_;
113
114 /** the users private resource bundle */
115 protected Properties user_properties_;
116
117 /** the file that holds the users resources */
118 protected File user_resource_file_;
119
120 /** the system resource base dir */
121 protected String user_resource_base_name_;
122
123 /** the user resource base dir */
124 protected String system_resource_base_name_;
125
126 /** the mapping holding all requested FileResources */
127 protected static WeakHashMap mapping_ = new WeakHashMap();
128
129 //----------------------------------------------------------------------
130 /**
131 * Creates a new FileResources class.
132 *
133 * @param user_resource_file the resource file of the user.
134 * @param user_bundle the user resource bundle.
135 * @param user_resource_base_name the file name of the user_bundles
136 * directory.
137 * @param system_bundle the system resource bundle.
138 * @param system_resource_base_name the file name of the
139 * system_bundles directory.
140 */
141
142 protected FileResources(File user_resource_file,
143 Properties user_bundle,
144 String user_resource_base_name,
145 ResourceBundle system_bundle,
146 String system_resource_base_name)
147 {
148 user_resource_file_ = user_resource_file;
149 user_properties_ = user_bundle;
150 if (user_properties_ == null)
151 user_properties_ = new Properties();
152 user_resource_base_name_ = user_resource_base_name;
153 system_bundle_ = system_bundle;
154 system_resource_base_name_ = system_resource_base_name;
155 }
156
157 //----------------------------------------------------------------------
158 /**
159 * Get the appropriate FileResources for the given base_name.
160 *
161 * @param base_name the base name of the resource bundle.
162 * @return the Resource.
163 * @exception MissingResourceException if the system resource file
164 * could not be located.
165 * @see #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)
166 */
167
168 public static FileResources getResources(String base_name)
169 throws MissingResourceException
170 {
171 return(getResources(null, base_name, base_name, null));
172 }
173
174 //----------------------------------------------------------------------
175 /**
176 * Get the appropriate FileResources for the given base_name and
177 * searches the system bundle in the callers package name.
178 * See also
179 * {@link #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)}
180 *
181 * @param caller the caller, to search the system bundle for.
182 * @param base_name the base name of the resource bundle.
183 * @return the Resource.
184 * @exception MissingResourceException if the system resource file
185 * @see #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)
186 */
187
188 public static FileResources getResources(Class caller,
189 String base_name)
190 throws MissingResourceException
191 {
192 return(getResources(caller, base_name, base_name, null));
193 }
194
195 //----------------------------------------------------------------------
196 /**
197 * Get the appropriate FileResources for the given base_name and the
198 * given locale.
199 *
200 * @param base_name the base name of the resource bundle.
201 * @param locale the locale.
202 * @return the Resource.
203 * @exception MissingResourceException if the system resource file
204 * could not be located.
205 * @see #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)
206 */
207
208 public static FileResources getResources(String base_name,
209 Locale locale)
210 throws MissingResourceException
211 {
212 return(getResources(null, base_name, base_name, locale));
213 }
214
215 //----------------------------------------------------------------------
216 /**
217 * Get the appropriate FileResources for the given base_name and locale
218 * and searches the system bundle in the callers package name. See
219 * also {@link
220 * #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)}
221 *
222 * @param caller the caller, to search the system bundle for.
223 * @param base_name the base name of the resource bundle.
224 * @param locale the locale.
225 * @return the Resource.
226 * @exception MissingResourceException if the system resource file
227 * could not be located.
228 * @see #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)
229 */
230
231 public static FileResources getResources(Class caller,
232 String base_name,
233 Locale locale)
234 throws MissingResourceException
235 {
236 return(getResources(caller, base_name, base_name, locale));
237 }
238
239
240 //----------------------------------------------------------------------
241 /**
242 * Get the appropriate FileResources for the given base_name and the
243 * given dir_name. The dir_name specifies the directory name of the
244 * users resource file, relative to the users home directory.
245 *
246 * @param base_name the base name of the resource bundle.
247 * @param dir_name the name of the directory within the users homedir
248 * to look for a property file.
249 * @return the Resource.
250 * @exception MissingResourceException if the system resource file
251 * could not be located.
252 * @see #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)
253 */
254
255 public static FileResources getResources(String base_name,
256 String dir_name)
257 throws MissingResourceException
258 {
259 return(getResources(null, base_name, dir_name, null));
260 }
261
262 //----------------------------------------------------------------------
263 /**
264 * Get the appropriate FileResources for the given base_name and the
265 * given dir_name and searches the system bundle in the callers
266 * package name. The dir_name specifies the directory name of the
267 * users resource file, relative to the users home directory.
268 *
269 * @param caller the caller, to search the system bundle for.
270 * @param base_name the base name of the resource bundle.
271 * @return the Resource.
272 * @param dir_name the name of the directory within the users homedir
273 * to look for a property file.
274 * @exception MissingResourceException if the system resource file
275 * could not be located.
276 * @see #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)
277 */
278
279 public static FileResources getResources(Class caller,
280 String base_name,
281 String dir_name)
282 throws MissingResourceException
283 {
284 return(getResources(caller, base_name, dir_name, null));
285 }
286
287 //----------------------------------------------------------------------
288 /**
289 * Get the appropriate FileResources for the given base_name, the given
290 * dir_name and the given locale. The dir_name specifies the
291 * directory name of the users resource file, relative to the users
292 * home directory.
293 *
294 * @param base_name the base name of the resource bundle.
295 * @param locale the locale.
296 * @param dir_name the name of the directory within the users homedir
297 * to look for a property file.
298 * @return the Resource.
299 * @exception MissingResourceException if the system resource file
300 * could not be located.
301 * @see #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)
302 */
303
304 public static FileResources getResources(String base_name,
305 String dir_name,
306 Locale locale)
307 throws MissingResourceException
308 {
309 return(getResources(null, base_name, dir_name, locale));
310 }
311
312 //----------------------------------------------------------------------
313 /**
314 * Get the appropriate ResourceBundle. The ResourceBundle consists
315 * of two parts, the system resources (for default settings) and
316 * user specific settings. Any given properties in the users
317 * resources will overwrite the system resources! The users
318 * resources are searched in the following order:
319 * $user_home/<code>dir_name</code>/<code>base_name</code>.properties,
320 * $user_home/.<code>dir_name</code>/<code>base_name</code>.properties,
321 * $user_home/<code>dir_name</code>.toLowerCase()/<code>base_name</code>.properties,
322 * $user_home/.<code>dir_name</code>.toLowerCase()/<code>base_name</code>.properties<p>
323 *
324 * The system resources are expected to be in the same package than
325 * the caller!<p>
326 *
327 * Example:<br>
328 * caller: <code>org.dinopolis.util.FileResources</code><br>
329 * base_name: <code>TestFileResources</code><br>
330 * dir_name: <code>test_resources</code><br>
331 * locale: <code>Locale.getDefault()</code><br>
332 * users home dir: ~dfreis<p>
333 *
334 * then, the users bundle is suspected to be:<br>
335 * "~dfreis/test_resources/TestFileResources.properties", or if not found:<br>
336 * "~dfreis/.test_resources/TestFileResources.properties"
337 *
338 * the system resources are expected to be in:<br>
339 * "org.dinopolis.util.FileResources.TestFileResources.properties"
340 * within your classpath!<p>
341 *
342 * The sample code of the caller for the given example will look
343 * like this:
344 * <xmp>
345 * FileResources resources = FileResources.getResources(getClass(), "TestFileResources",
346 * "test_resources");
347 * </xmp>
348 *
349 * @param caller the caller, to search the system bundle for.
350 * @param base_name the base name of the resource bundle.
351 * @param dir_name the name of the directory within the users homedir
352 * to look for a property file.
353 * @param locale the locale.
354 * @return the Resource.
355 * @exception MissingResourceException if the system resource file
356 * could not be located.
357 */
358
359 public static FileResources getResources(Class caller,
360 String base_name,
361 String dir_name,
362 Locale locale)
363 throws MissingResourceException
364 {
365 return(getResources(caller,base_name,dir_name,locale,null));
366 }
367
368 //----------------------------------------------------------------------
369 /**
370 * Get the appropriate ResourceBundle with the use of the given
371 * classloader.
372 *
373 * @param caller the caller, to search the system bundle for.
374 * @param base_name the base name of the resource bundle.
375 * @param dir_name the name of the directory within the users homedir
376 * to look for a property file.
377 * @param locale the locale.
378 * @param loader the class loader to use (if null, the class loader
379 * of the caller is used (or of the FileResource class, if call is null)).
380 * @return the Resource.
381 * @exception MissingResourceException if the system resource file
382 * could not be located.
383 * @see #getResources(java.lang.Class,java.lang.String,java.lang.String,java.util.Locale)
384 */
385
386 public static FileResources getResources(Class caller,
387 String base_name,
388 String dir_name,
389 Locale locale,
390 ClassLoader loader)
391 throws MissingResourceException
392 {
393 String system_resource_base_name =
394 getSystemResourceBaseName(caller);
395 String user_resource_base_name = getUserResourceBaseName(dir_name);
396 File user_resource_file = getUsersResourceFile(base_name, user_resource_base_name);
397
398 String key = locale+":"+base_name+":"+system_resource_base_name+
399 ":"+user_resource_base_name;
400 FileResources bound = (FileResources)mapping_.get(key);
401 if (bound == null)
402 {
403 if(loader == null)
404 {
405 if(caller == null)
406 loader = FileResources.class.getClassLoader();
407 else
408 loader = caller.getClassLoader();
409 }
410 bound = new FileResources(user_resource_file,
411 getUsersResourceBundle(user_resource_file),
412 user_resource_base_name,
413 getSystemResourceBundle(system_resource_base_name,
414 base_name, locale, loader),
415 system_resource_base_name);
416 mapping_.put(key, bound);
417 }
418 return(bound);
419 }
420
421 //----------------------------------------------------------------------
422 /**
423 * Returs the base name of the system resource bundle. The base name
424 * corresponds to the callers package name.
425 *
426 * @param caller the caller.
427 * @return the base name of the resource bundle.
428 */
429
430 protected static String getSystemResourceBaseName(Class caller)
431 {
432 if (caller == null)
433 return("");
434 String caller_package = caller.getName();
435 int las_dot = caller_package.lastIndexOf('.');
436 if (las_dot > 0)
437 caller_package = caller_package.substring(0, las_dot);
438 else
439 caller_package = "";
440 return(caller_package.replace('.','/'));
441 }
442
443 //----------------------------------------------------------------------
444 /**
445 * Returns the system resource bundle.
446 *
447 * @param system_resource_base_dir he base directory of the system
448 * resource bundle.
449 * @param base_name he base name of the resource file.
450 * @param locale the locale (if null, the default locale is used.)
451 * @param loader the class loader to use.
452 * @return the system resource bundle if found.
453 * @exception MissingResourceException if the system resource file
454 * could not be located.
455 */
456
457 protected static ResourceBundle getSystemResourceBundle(String system_resource_base_dir,
458 String base_name,
459 Locale locale,
460 ClassLoader loader)
461 throws MissingResourceException
462 {
463 String resource = system_resource_base_dir;
464 if (resource.length() > 0)
465 resource += ".";
466 resource += base_name;
467 if (locale != null)
468 return(ResourceBundle.getBundle(resource, locale,loader));
469 return(ResourceBundle.getBundle(resource,Locale.getDefault(),loader));
470 }
471
472 //----------------------------------------------------------------------
473 /**
474 * Returns the path of the users resource bundle.
475 * The Resource bundle is searched in the following order:
476 * $user_home/<code>dir_name</code>,
477 * $user_home/.<code>dir_name</code>,
478 * $user_home/<code>dir_name</code>.toLowerCase(),
479 * $user_home/.<code>dir_name</code>.toLowerCase().
480 *
481 * @param dir_name the name of the directory within the users homedir
482 * to look for a property file.
483 * @return the base name of the resource bundle, or null if no dir was
484 * found.
485 */
486
487 protected static String getUserResourceBaseName(String dir_name)
488 {
489 File home_dir = new File(System.getProperty("user.home"));
490 File resource_dir = new File(home_dir, dir_name);
491 if (!resource_dir.isDirectory())
492 resource_dir = new File(home_dir, "."+dir_name); // add a dot in front
493 if (!resource_dir.isDirectory())
494 resource_dir = new File(home_dir, dir_name.toLowerCase()); // try it lowercased
495 if (!resource_dir.isDirectory())
496 resource_dir = new File(home_dir, "."+dir_name.toLowerCase()); // try it lowercased and added dot
497
498 if (!resource_dir.isDirectory())
499 // directory not found! -> use standard way
500 resource_dir = new File(home_dir, dir_name.toLowerCase());
501 return(resource_dir.getPath());
502 }
503
504 //----------------------------------------------------------------------
505 /**
506 * Returns the user resource file. located in
507 * <code>user_resource_dir</code> with the base name
508 * <code>base_name</code>.
509 *
510 * @param base_name he base name of the users resource file.
511 * @param user_resource_dir the name of the directory within the users
512 * homedir to look for a property file.
513 * @return the resource file found in the users home dir.
514 */
515
516 protected static File getUsersResourceFile(String base_name,
517 String user_resource_dir)
518 {
519 File resource_dir;
520 if (user_resource_dir == null)
521 resource_dir = new File(System.getProperty("user.home"));
522 else
523 resource_dir = new File(user_resource_dir);
524 return(new File(resource_dir, base_name+PROPERTY_EXTENSION));
525 }
526
527 //----------------------------------------------------------------------
528 /**
529 * Returns the user resource bundle.
530 *
531 * @param user_resource_file the users resource file
532 * @return the resource bundle found in the users home dir, or null if
533 * no resource file exists.
534 */
535
536 protected static Properties getUsersResourceBundle(File
537 user_resource_file)
538 {
539 if (!user_resource_file.isFile())
540 return(null);
541
542 try
543 {
544 Properties properties = new Properties();
545 properties.load(new
546 FileInputStream(user_resource_file));
547 return(properties);
548 }
549 catch (FileNotFoundException exc)
550 {
551 // silently ignored
552 }
553 catch (IOException exc)
554 {
555 // silently ignored
556 }
557 return(null);
558 }
559
560 //----------------------------------------------------------------------
561 /**
562 * Returns true, if this resources is capable of storing and
563 * deleting resources, false otherwise.
564 *
565 * @return true, if this resources is capable of storing and
566 * deleting resources, false otherwise.
567 */
568
569 public boolean isModificationSupported()
570 {
571 return(true);
572 }
573
574 //----------------------------------------------------------------------
575 /**
576 * Gets the bound value for the given key.
577 *
578 * @param key the key of the resource property to look for.
579 * @return the string loaded from the resource bundle.
580 * @throws MissingResourceException if the value is not found.
581 */
582
583 protected synchronized String getValue(String key)
584 throws MissingResourceException
585 {
586 String value = user_properties_.getProperty(key);
587 if (value != null)
588 return(value);
589 return(system_bundle_.getString(key)); // the system bundle
590 }
591
592 //----------------------------------------------------------------------
593 /**
594 * Returns an Enumeration containing all keys of all resources.
595 *
596 * @return an Enumeration containing all keys of all resources.
597 */
598
599 protected Enumeration doGetKeys()
600 {
601 return(new FileResourcesEnumeration());
602 }
603
604 //----------------------------------------------------------------------
605 /**
606 * Registers the given value under the given key. Key and value are
607 * garanteed to be non-null!
608 * Overwrite this method in classes extending AbstractResources if
609 * set methods are supported.
610 *
611 * @param key the key of the resource property to set.
612 * @param value the value of the resource property to set.
613 *
614 */
615
616 protected synchronized void setValue(String key, String value)
617 {
618 // System.err.println("setValue() key: "+key+", value: "+value);
619 user_properties_.setProperty(key, value);
620 }
621
622 //----------------------------------------------------------------------
623 /**
624 * Removes the bound value for the given key, if no value was bound
625 * under the given key, this method does nothing. Key is garanteed
626 * to be non-null!
627 * Overwrite this method in classes extending AbstractResources, if
628 * remove is supported.
629 *
630 * @param key the key of the resource to delete.
631 */
632
633 protected synchronized void unsetValue(String key)
634 {
635 // System.err.println("unsetValue() key: "+key);
636 try
637 {
638 system_bundle_.getString(key);
639 }
640 catch(Exception e)
641 {
642 user_properties_.remove(key); // it was not in the system bundle
643 return;
644 }
645 // mark it with a special key, so it is unset from now on!
646 user_properties_.put(key,"$"+UNSET_KEY+"$");
647 }
648
649 //----------------------------------------------------------------------
650 /**
651 * Resets the bound value for the given key to its default value. If
652 * no value was bound under the given key, this method does
653 * nothing. Key is garanteed to be non-null! Removes the value from
654 * the user properties.
655 *
656 * @param key the key of the resource to reset.
657 */
658
659 protected void resetValue(String key)
660 {
661 user_properties_.remove(key);
662 }
663
664 //----------------------------------------------------------------------
665 /**
666 * Call this method to make all changes performed by unset and
667 * setter methods persistent.
668 * Overwrite this method in classes extending AbstractResources, if
669 * modifications are supported.
670 *
671 * @exception IOException in case of an IOError.
672 */
673
674 protected synchronized void doStore()
675 throws IOException
676 {
677 String tmp_file_name = user_resource_file_.getName()+".tmp";
678 File parent = user_resource_file_.getParentFile();
679 if (!parent.exists())
680 parent.mkdir();
681
682 FileOutputStream file_out = new FileOutputStream(user_resource_file_);
683 user_properties_.store(file_out, "auto generated file - by FileResources");
684 file_out.close();
685 return;
686 }
687
688
689 //----------------------------------------------------------------------
690 /**
691 * Returns the title for the given key. If no title for this key is
692 * available, <code>null</code> is returned.
693 * Overwrite this method in classes extending AbstractResources, if
694 * titles are supported. by default, this method returns null.
695 *
696 * @param key the key to get the title for.
697 * @return the title for the given key.
698 */
699
700 public String getTitle(String key)
701 {
702 return(getString(key+TITLE_SUFFIX, null));
703 }
704
705 //----------------------------------------------------------------------
706 /**
707 * Sets the title for the given key.
708 * Deleted the title if title is 'null'.
709 *
710 * @param key the key to set the title for.
711 * @param title the title to set.
712 * @exception IllegalArgumentException if key is 'null'.
713 */
714
715 public void setTitle(String key, String title)
716 {
717 if (title == null)
718 unsetValue(key+TITLE_SUFFIX);
719 setValue(key+TITLE_SUFFIX, title);
720 }
721
722 //----------------------------------------------------------------------
723 /**
724 * Returns a string that describes the key and its possible values.
725 * If no description for this key is available, <code>null</code> is
726 * returned.
727 * Overwrite this method in classes extending AbstractResources, if
728 * descriptions are supported. by default, this method returns null.
729 *
730 * @param key the key to get the description for.
731 * @return the description of the given key and its possible values.
732 */
733
734 public String getDescription(String key)
735 {
736 return(getString(key+DESCRIPTION_SUFFIX, null));
737 }
738
739 //----------------------------------------------------------------------
740 /**
741 * Sets the description for the given key.
742 * Deleted the description if description is 'null'.
743 *
744 * @param key the key to set the description for.
745 * @param description the description to set.
746 * @exception IllegalArgumentException if key is 'null'.
747 */
748
749 public void setDescription(String key, String description)
750 {
751 if (description == null)
752 unsetValue(key+DESCRIPTION_SUFFIX);
753 setValue(key+DESCRIPTION_SUFFIX, description);
754 }
755
756 //----------------------------------------------------------------------
757 /**
758 * Returns the type of the value bound under the given key. Note
759 * that the returned "Class" object may describe a built-in Java
760 * type such as "int" (Integer.TYPE). For arrays, this may be e.g.:
761 * <code>int[].class</code>. If no type for this key is available,
762 * <code>null</code> is returned.
763 * Overwrite this method in classes extending AbstractResources, if
764 * types are supported. by default, this method returns null.
765 *
766 * @param key the key to get the type for.
767 * @return the type of the value bound under the given key.
768 */
769
770 public Class getType(String key)
771 {
772 String class_name = getString(key+TYPE_SUFFIX, null);
773 return(getClassForType(class_name));
774 }
775
776 //----------------------------------------------------------------------
777 /**
778 * Sets the type for the given key.
779 * Deleted the kype if type is 'null'.
780 *
781 * @param key the key to set the type for.
782 * @param type the type to set.
783 * @exception IllegalArgumentException if key is 'null'.
784 */
785
786 public void setType(String key, Class type)
787 {
788 String class_name = getTypeForClass(type);
789 if (class_name == null)
790 unsetValue(key+TYPE_SUFFIX);
791 else
792 setValue(key+TYPE_SUFFIX, class_name);
793 }
794
795 //----------------------------------------------------------------------
796 /**
797 * Returns an array of all values that are valid. This is usefull if
798 * a value may be choosen out of a predifined set of possible
799 * values.
800 * If no set of valid values exists <code>null</code> is returned.
801 * Overwrite this method in classes extending AbstractResources, if
802 * types is a set of chooseable values. by default, this method
803 * returns null.
804 *
805 * @param key the key to get the type for.
806 * @return the possible values.
807 */
808
809 public String[] getPossibleValues(String key)
810 {
811 return(getStringArray(key+POSSIBLE_VALUES_SUFFIX,
812 (String[])null));
813 }
814
815 //----------------------------------------------------------------------
816 /**
817 * Sets the possible Values for the given key.
818 * Deleted the possible Values if possible_values are 'null'.
819 *
820 * @param key the key to set the possible Values for.
821 * @param possible_values the possible Values to set.
822 * @exception IllegalArgumentException if is 'null'.
823 */
824
825 public void setPossibleValues(String key, String[] possible_values)
826 {
827 if (possible_values == null)
828 unsetValue(key+POSSIBLE_VALUES_SUFFIX);
829 else
830 setStringArray(key+POSSIBLE_VALUES_SUFFIX, possible_values);
831 }
832
833 //----------------------------------------------------------------------
834 /**
835 * Returns the Url loaded from the resource bundle. The key in the
836 * resource file may be relative to the resource file. Any variables
837 * found within the properties value will be replaced.
838 *
839 * @param key the key of the resource property to look for.
840 * @return the Url that is loaded from the resource bundle.
841 * @exception MissingResourceException if the given key is not defined
842 * within the resources, or is not a valid Url.
843 */
844
845 public URL getURL(String key)
846 throws MissingResourceException
847 {
848 String value = getString(key);
849 if (value == null)
850 return(null);
851 try
852 {
853 return(new URL(value));
854 }
855 catch (MalformedURLException exc)
856 {
857 // try it from private resource file ...
858 File file = new File(user_resource_base_name_, value);
859 if (file.exists())
860 {
861 try
862 {
863 return(file.toURL());
864 }
865 catch (MalformedURLException exc2)
866 {
867 // ignored
868 }
869 }
870
871 // try it with class loader
872 URL ret = ClassLoader.getSystemResource(system_resource_base_name_+"/"+value);
873 if (ret == null) // try it without base name
874 ret = ClassLoader.getSystemResource(value);
875
876 if (ret != null)
877 return(ret);
878
879 throw(new MissingResourceException("malformed URL '"+value+"'",
880 getClass().getName(), key));
881 }
882 }
883
884 //----------------------------------------------------------------------
885 /**
886 * The Enumeration for this FileResources.
887 *
888 * @author Dieter Freismuth
889 * @version $Revision: 1.7 $
890 */
891
892 class FileResourcesEnumeration implements Enumeration
893 {
894 protected Enumeration enum_;
895
896 //----------------------------------------------------------------------
897 /**
898 */
899
900 FileResourcesEnumeration()
901 {
902 HashSet added = new HashSet();
903 Vector keys = new Vector();
904 Enumeration enum = system_bundle_.getKeys();
905 String key;
906 while (enum.hasMoreElements())
907 {
908 key = (String)enum.nextElement();
909 if ((!added.contains(key)) &&
910 (!isSpecial(key)))
911 {
912 keys.add(key);
913 added.add(key);
914 }
915 }
916 enum = user_properties_.propertyNames();
917 while (enum.hasMoreElements())
918 {
919 key = (String)enum.nextElement();
920 if ((!added.contains(key)) &&
921 (!isSpecial(key)))
922 {
923 keys.add(key);
924 added.add(key);
925 }
926 }
927 enum_ = keys.elements();
928 }
929
930 //----------------------------------------------------------------------
931 /**
932 * @param key the key to check for.
933 * @return if the key is an extension to a resource, ending with
934 * .type, .description, .title or .possible_values.
935 */
936
937 protected boolean isSpecial(String key)
938 {
939 int delimiter = key.lastIndexOf(".");
940 if (delimiter <= 0)
941 return(false);
942 if ((!key.endsWith(TITLE_SUFFIX)) &&
943 (!key.endsWith(DESCRIPTION_SUFFIX)) &&
944 (!key.endsWith(TYPE_SUFFIX)) &&
945 (!key.endsWith(POSSIBLE_VALUES_SUFFIX)))
946 return(false);
947 return(true);
948 }
949
950 //----------------------------------------------------------------------
951 /**
952 * Tests if this enumeration contains more elements.
953 *
954 * @return <code>true</code> if and only if this enumeration object
955 * contains at least one more element to provide;
956 * <code>false</code> otherwise.
957 */
958
959 public boolean hasMoreElements()
960 {
961 return(enum_.hasMoreElements());
962 }
963
964 //----------------------------------------------------------------------
965 /**
966 * Returns the next element of this enumeration if this enumeration
967 * object has at least one more element to provide.
968 *
969 * @return the next element of this enumeration.
970 * @exception NoSuchElementException if no more elements exist.
971 */
972 public Object nextElement()
973 {
974 return(enum_.nextElement());
975 }
976 }
977 }
978
979
980
981
982
983
984
985
986
987
988