KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ixenon > free > util > ApplicationResources


1 /* $Id$
2  *
3  * Copyright (c) 1999 Xenonsoft Limited. All Rights Reserved.
4  *
5  * This software is protected by copyright. You are hereby notified from
6  * now by reading this message. This software is also the confidential
7  * and proprietary information of Xenonsoft Limited. ("Confidential
8  * Information").
9  *
10  * This software is distributed under the Xenonsoft Public end user
11  * License ("XPeL"), where the machine-readable source code is provided
12  * under the "Open Source" model.
13  * For more information, please read the file "LICENSE-XPL.txt"
14  */

15
16 // ApplicationResources.java
17

18 //
19
// Description:
20
// ApplicationResources designed to hold an applications
21
// resources bundle for internationalization.
22
//
23
//
24
//
25
// Author:
26
// Peter Pilgrim
27
// Mon Jul 27 23:16:17 BST 1998
28
//
29
// RCS HEADER ``ApplicationResources.java''
30
//
31
// $Author$
32
// $Date$
33
// $Source$
34
// $Revision$ $State$ $Locker$
35
//
36
// History
37
// ================================================================================
38
// $Log$
39
//
40

41 package ixenon.free.util;
42
43 import java.io.*; // IO Classes
44
import java.net.*; // Network/Internet classes
45
import java.awt.Image JavaDoc; // AWT Image class
46
import java.awt.Font JavaDoc; // AWT Font class
47
import java.awt.FontMetrics JavaDoc; // AWT FontMetrics class
48
import java.awt.Color JavaDoc; // AWT Color class
49
import java.awt.Toolkit JavaDoc; // AWT Toolkit class
50
import java.awt.image.*; // image package
51
// import java.util.zip.*; // ZipInputStream class etc
52

53 import java.util.Enumeration JavaDoc; // Enumeration
54
import java.util.Hashtable JavaDoc; // Hashtable
55
import java.util.StringTokenizer JavaDoc; // String Tokenizer
56
import java.util.Locale JavaDoc; // Internationalisation (i18n)
57
import java.util.ResourceBundle JavaDoc;
58 import java.util.MissingResourceException JavaDoc;
59
60 /**
61  * A general class for locating and resolving application resources for
62  * any Java application or applet.
63  *
64  * The class relies on a system property <B>env.JAVAFILESEARCHPATH</B>,
65  * which defines a path list of directories or URL (Universal Resource
66  * Locators).
67  *
68  * For the <B>env.JAVAFILESEARCHPATH</B> could be defined as:
69  *
70  * "%N%S ; %T/%N%S ; %P/%T/%N%S ; %H/%T/%N%S ; %H/%N%S ; " +
71  * "/usr/local/%T/%N%S ; /usr/local/%N%S ; %Z/%T/%N%S ; %Z/%N%S "
72  *
73  *
74  * Please note the search path uses a semi-colon character (`;') as a path
75  * separator. This allows the path to include a URL specification. The path
76  * may contain any number of tokens beginning with percent (`%')
77  * character. These special key tokens are substituted with the real value
78  * at run time. Here is list of key tokens used in the software:
79  *
80  * <PRE>
81  * %P specifies the installed root of the application (PREFIX).
82  * Also set by the system property `env.PREFIX'
83  * %B specifies the installed root the application (EXEC_PREFIX).
84  * Also set by the system property `env.EXEC_PREFIX'
85  * %H specifies the users directory (HOME).
86  * %A specifies the audio file directory.
87  * Also set by the system property `env.AUDIO_DIR'
88  * %I specifies the graphics images file directory.
89  * Also set by the system property `env.IMAGES_DIR'
90  * %T specifies the type (as above)
91  * %N specifies the name (as above)
92  * %S specifies the suffix (as above)
93  * %Z specifies the webroot (an internet URL).
94  * Also set by the system property `env.WEB_ROOT_URL'
95  *
96  * For internationalisation (i18n)
97  * %L specifies the Locale string e.g `en_uk'.
98  * %l specifies the Locale language string e.g `en'.
99  * %t specifies the Locale country string e.g `uk'.
100  * %v specifies the Locale variant string e.g. `Traditional_Win'.
101  * <PRE>
102  *
103  * A further and final example should make the ``process of resolution'' clear.
104  * Suppose we are looking an image file called `monalisa.jpg' then it would be
105  * logically to have the type as `images', the name as `monalisa' and the
106  * suffix as `.jpg'. As a result we have the following definitions for a
107  * our key tokens:
108  *
109  * <PRE>
110  * %T = "images"
111  * %N = "monalisa"
112  * %S = ".jpg"
113  * </PRE>
114  *
115  *
116  * If we substitute values of the key tokens in the application resource
117  * search path from the first example then we end up with a search sequence
118  * of the form:
119  *
120  *
121  * <PRE>
122  * 1) images/monalisa.gif
123  * 2) monalisa.gif
124  * 3) /usr/mogwai/images/monalisa.gif
125  * 4) /usr/mogwai/monalisa.gif
126  * 5) /usr/local/images/monalisa.gif
127  * 6) /usr/local/monalisa.gif
128  * </PRE>
129  *
130  *
131  * ( The idea of the environment variable `JAVAFILESEARCHPATH'' came
132  * originally from the X Window Intrinsic System's `XFILESEARCHPATH'. I
133  * always loved the way `X' did it's thing, so I implemented a similar
134  * application resource search path in Java. *PP*)
135  *
136  */

137 public final class ApplicationResources
138 {
139     public static boolean debug=false; // Debuggable
140

141     /** Installed Root of Application */
142     public final String JavaDoc PREFIX_DIR = "__PREFIX__";
143
144     /** Installed Root of Binaries */
145     public final String JavaDoc EXEC_PREFIX_DIR = "__EXEC_PREFIX__";
146                 
147     /** Where can I find images */
148     public final String JavaDoc IMAGES_DIR = "__IMAGE_DIR__";
149                 
150     /** Where can I find audio files */
151     public final String JavaDoc AUDIO_DIR = "__AUDIO_DIR__";
152
153     /** Web page root */
154     public final String JavaDoc WEB_ROOT_URL = "__URL__";
155     
156     /**
157      * internal static member which is the singleton
158      * @see #createInstance
159      * @see #getInstance
160      */

161     private static ApplicationResources singleton=null;
162     private ResourceBundle JavaDoc bundle;
163     private String JavaDoc appClassName;
164     private String JavaDoc searchPath;
165     private String JavaDoc prefix;
166     private String JavaDoc execPrefix;
167     private String JavaDoc audioDir;
168     private String JavaDoc imagesDir;
169     private String JavaDoc webRootURL;
170     
171     /** The default image name */
172     public final String JavaDoc DEFAULT_IMAGE_NAME="default_image";
173     
174     /** Internal default image @see java.awt.Image */
175     private static Image JavaDoc imageDefault=null;
176     
177     /** Internal cache for images @see java.awt.Image */
178     private static Hashtable JavaDoc imageCache=null;
179
180     // Java hex dump byte data from file:../images/danger-sign.gif
181
private static byte DEFAULT_IMAGE_DATA[] = {
182     (byte)0x47, (byte)0x49, (byte)0x46, (byte)0x38, (byte)0x39, (byte)0x61, (byte)0x18, (byte)0x0, (byte)0x18, (byte)0x0,
183     (byte)0xc2, (byte)0x0, (byte)0x0, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0xff,
184     (byte)0x0, (byte)0x0, (byte)0xff, (byte)0xff, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x80, (byte)0xff, (byte)0xff,
185     (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x21, (byte)0xfe, (byte)0xe,
186     (byte)0x4d, (byte)0x61, (byte)0x64, (byte)0x65, (byte)0x20, (byte)0x77, (byte)0x69, (byte)0x74, (byte)0x68, (byte)0x20,
187     (byte)0x47, (byte)0x49, (byte)0x4d, (byte)0x50, (byte)0x0, (byte)0x2c, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0,
188     (byte)0x18, (byte)0x0, (byte)0x18, (byte)0x0, (byte)0x0, (byte)0x3, (byte)0x65, (byte)0x8, (byte)0xba, (byte)0xdc,
189     (byte)0xfe, (byte)0x2f, (byte)0x4, (byte)0x48, (byte)0x59, (byte)0x10, (byte)0x62, (byte)0x56, (byte)0x78, (byte)0x71,
190     (byte)0xde, (byte)0x91, (byte)0xf7, (byte)0x81, (byte)0x96, (byte)0x88, (byte)0x69, (byte)0x24, (byte)0xd0, (byte)0xd,
191     (byte)0xc3, (byte)0x99, (byte)0xaa, (byte)0x1e, (byte)0xeb, (byte)0xa1, (byte)0xdb, (byte)0xca, (byte)0xb6, (byte)0x63,
192     (byte)0x1d, (byte)0x13, (byte)0x4, (byte)0x9e, (byte)0x53, (byte)0x36, (byte)0x9e, (byte)0xec, (byte)0x17, (byte)0xc2,
193     (byte)0xb0, (byte)0x84, (byte)0x3e, (byte)0x9a, (byte)0xc3, (byte)0x36, (byte)0x40, (byte)0xe2, (byte)0x94, (byte)0x25,
194     (byte)0xe3, (byte)0xb1, (byte)0x37, (byte)0x24, (byte)0x2e, (byte)0x98, (byte)0x4d, (byte)0xea, (byte)0x10, (byte)0xa,
195     (byte)0x93, (byte)0x4e, (byte)0x6f, (byte)0xc9, (byte)0xa5, (byte)0x17, (byte)0x4c, (byte)0x76, (byte)0x45, (byte)0x5,
196     (byte)0x64, (byte)0x67, (byte)0x95, (byte)0x86, (byte)0xfd, (byte)0x96, (byte)0x73, (byte)0x1d, (byte)0x34, (byte)0x79,
197     (byte)0xbe, (byte)0x56, (byte)0xc4, (byte)0x4d, (byte)0x78, (byte)0xbc, (byte)0xe6, (byte)0x9e, (byte)0xef, (byte)0xc3,
198     (byte)0x25, (byte)0x80, (byte)0x81, (byte)0x82, (byte)0x82, (byte)0x2f, (byte)0x1b, (byte)0x9, (byte)0x0, (byte)0x3b,
199     };
200     
201     /** private method, because this is a SINGLETON class
202      * @param bundle the resource bundle
203      * @param appClassName the application class name
204      */

205     private ApplicationResources( ResourceBundle JavaDoc bundle, String JavaDoc appClassName )
206     {
207     // System.out.println( "env=" + System.getProperty("env") );
208
this.bundle = bundle;
209     this.appClassName = appClassName;
210     String JavaDoc osname = System.getProperty("os.name");
211     String JavaDoc fileSep = System.getProperty("file.separator");
212     String JavaDoc userHome = System.getProperty("user.home");
213     
214     //
215
// Set default property file for the environment and
216
// install it the home directory
217
//
218
String JavaDoc propFile;
219     if ( osname.startsWith("Windows 95") ||
220          osname.startsWith("Windows 98") ||
221          osname.startsWith("Windows NT") ||
222          osname.startsWith("Windows 2000") ||
223          osname.startsWith("OS/2") )
224         // e.g. C:\_FreeInstaller\FreeInstaller.properties
225
propFile = "_" + appClassName + fileSep + appClassName + ".properties";
226     else
227         // e.g. /home/peterp/.FreeInstaller/FreeInstaller.properties
228
propFile = "." + appClassName + fileSep + appClassName +".properties";
229     
230     //
231
// The list of environment variables stored in the system
232
// property `env' are transformed as separate properties
233
// prefixed with `env.'
234
//
235
Environment.readEnvironment( normalizePathname(propFile) );
236
237     if ( System.getProperty("env.DEBUG_RESOURCES") != null)
238         // Switch on debugging of application resources
239
debug=true;
240     
241     prefix = System.getProperty( "env.PREFIX", PREFIX_DIR );
242     execPrefix = System.getProperty( "env.EXEC_PREFIX", EXEC_PREFIX_DIR );
243     audioDir = System.getProperty( "env.AUDIO_DIR", AUDIO_DIR );
244     imagesDir = System.getProperty( "env.IMAGES_DIR", IMAGES_DIR );
245     webRootURL = System.getProperty( "env.WEB_ROOT_URL", WEB_ROOT_URL );
246
247     if (debug) {
248         System.out.println( "(*DEBUG*) Creating application resources:");
249         System.out.println( " prefix=`"+prefix+"'");
250         System.out.println( " exec_prefix=`"+execPrefix+"'");
251         System.out.println( " audio_dir=`"+audioDir+"'");
252         System.out.println( " images_dir=`"+imagesDir+"'");
253         System.out.println( "web_root_url=`"+webRootURL+"'");
254     }
255     }
256     
257     /**
258      * get the application resources instance or creates singleton
259      * if it did not exist.
260      *
261      * @param bundle the resource bundle
262      * @param appClassName the application class name
263      */

264     public static ApplicationResources createInstance( ResourceBundle JavaDoc bundle, String JavaDoc appClassName )
265     {
266     // Only one object can be created.
267
if (singleton == null)
268         singleton = new ApplicationResources( bundle, appClassName );
269     return (singleton);
270     }
271
272     /** Retrieves the singleton instance: there can only be one
273      * application resource per program.
274      *
275      * @return the singleton application resources.
276      */

277     public static ApplicationResources getInstance()
278     {
279     // Only one object can be created.
280
if (singleton == null)
281         throw new NullPointerException JavaDoc( "no singleton was ever created!" );
282     return (singleton);
283     }
284
285     /** Returns the resource bundle */
286     public ResourceBundle JavaDoc getResourceBundle()
287     {
288     return (bundle);
289     }
290
291     /**
292      * Dynamically create the default search path for application
293      *
294      *
295      * Default Search Path separated by the semi-colon (";")
296      * This is because the search path can contain URL specifications
297      * i.e url:www.foobar.com/audio for example
298      * TOO BAD: it wont work with Digitals VMS files with version suffixes.
299      *
300      * On UNIX operating system
301      *
302      * "%T/%L/%N%S ; %T/%N%S ; %N%S
303      * %H/%T/%L/%N%S ; %H/%T/%N%S ; %H/%N%S
304      * %P/%T/%L/%N%S ; %P/%T/%N%S ; %P/%N%S
305      * /usr/local/%T/%L/%N%S ; /usr/local/%T/%N%S ; /usr/local/%N%S ;
306      * %Z/%T/%L/%N%S ; %Z/%T/%N%S ; %Z/%N%S;
307      *
308      * "%T/%N_%L%S ; %T/%N%S ; %N_%L%S ; %N%S ;
309      * %H/%T/%N_%L%S ; %H/%T/N%S ; %H/%N_%L%S ; %H/%N%S ;
310      * %P/%T/%N_%L%S ; %P/%T/N%S ; %P/%N_%L%S ; %P/%N%S ;
311      * /usr/local/%T/%N_%L%S ; /usr/local/%T/%N%S ; /usr/local/%N%S ;
312      * %Z/%T/%N_%L%S ; %Z/%T/%N%S ; %Z/%N_%L%S; %Z/%N%S;
313      */

314     public static String JavaDoc getDefaultApplicationSearchPath()
315     {
316     // "/usr/local/lib/classes/%T/%N%S ; /usr/local/lib/classes/%N%S ; " +
317
StringBuffer JavaDoc defPath = new StringBuffer JavaDoc();
318     String JavaDoc osname = System.getProperty("os.name");
319     String JavaDoc pathSep = System.getProperty("path.separator");
320     String JavaDoc fileSep = System.getProperty("file.separator");
321     
322     defPath.append( "%T/%L/%N%S;" );
323     defPath.append( "%T/%N%S;" );
324     defPath.append( "%N%S;" );
325     defPath.append( "%H"+fileSep+"%T"+fileSep+"%L"+fileSep+"%N%S;" );
326     defPath.append( "%H"+fileSep+"%T"+fileSep+"%N%S;" );
327     defPath.append( "%H"+fileSep+"%N%S;" );
328     defPath.append( "%P"+fileSep+"%T"+fileSep+"%L"+fileSep+"%N%S;" );
329     defPath.append( "%P"+fileSep+"%T"+fileSep+"%N%S;" );
330     defPath.append( "%P"+fileSep+"%N%S;" );
331
332     if (osname.startsWith("Windows 95") ||
333         osname.startsWith("Windows 98") ||
334         osname.startsWith("Windows NT")) {
335         defPath.append( "C:\\Program Files\\Default"+fileSep+"%T"+fileSep+"%L"+fileSep+"%N%S;");
336         defPath.append( "C:\\Program Files\\Default"+fileSep+"%T"+fileSep+"%N%S;");
337         defPath.append( "C:\\Program Files\\Default"+fileSep+"%N%S;");
338     }
339     else {
340         // For UNIX like system append "/usr/local"
341
defPath.append( fileSep+"usr"+fileSep+"local"+fileSep+"%T"+fileSep+"%L"+fileSep+"%N%S;" );
342         defPath.append( fileSep+"usr"+fileSep+"local"+fileSep+"%T"+fileSep+"%N%S;" );
343         defPath.append( fileSep+"usr"+fileSep+"local"+fileSep+"%N%S;" );
344     }
345
346     if (debug)
347         System.out.println("*DEBUG* calculated default search path = `" +
348                    defPath.toString() + "'" );
349     // defPath.append( "%Z"+fileSep+"%N%S;%Z"+fileSep+"%T"+fileSep+"%N%S;" );
350
return defPath.toString();
351     }
352     
353     /** This is convenience helper to get the a string
354      * from the application resources.
355      * @param name the resource name
356      * @param def the default value as a string
357      */

358     public String JavaDoc getResourceString( String JavaDoc name, String JavaDoc def )
359     {
360     String JavaDoc ret;
361     
362     try { ret = bundle.getString( appClassName + "." + name ); }
363     catch (MissingResourceException JavaDoc e) { ret = def; }
364     return (ret);
365     }
366         
367     /** This is convenience helper to get the an mnemonic
368      * from the application resources.
369      * @param name the resource name
370      * @param def the default mnemonic
371      */

372     public int getResourceMnemonic( String JavaDoc name, int def )
373     {
374         int ret;
375     
376     try {
377         String JavaDoc temp = bundle.getString( appClassName + "." + name );
378         // System.out.println( "temp:" + temp );
379
ret = (temp != null) ? temp.charAt(0) : def;
380         
381     }
382     catch (MissingResourceException JavaDoc e) { ret = def; }
383     return (ret);
384     }
385
386     /** This is convenience helper to get the a integer value
387      * from the application resources.
388      * @param name the resource name
389      * @param def the default integer value
390      */

391     public int getResourceInteger( String JavaDoc name, int def )
392     {
393         int ret;
394     
395     try {
396         String JavaDoc temp = bundle.getString( appClassName + "." + name );
397         // System.out.println( "temp:" + temp );
398
ret = (temp != null) ? Integer.parseInt( temp.trim() ) : def;
399         
400     }
401     catch (MissingResourceException JavaDoc e) { ret = def; }
402     return (ret);
403     }
404
405     /** This is convenience helper to get the a long integer value
406      * from the application resources.
407      * @param name the resource name
408      * @param def the default long integer value
409      */

410     public long getResourceLong( String JavaDoc name, long def )
411     {
412         long ret;
413     
414     try {
415         String JavaDoc temp = bundle.getString( appClassName + "." + name );
416         // System.out.println( "temp:" + temp );
417
ret = (temp != null) ? Long.parseLong( temp.trim() ) : def;
418         
419     }
420     catch (MissingResourceException JavaDoc e) { ret = def; }
421     return (ret);
422     }
423
424     /** This is convenience helper to get the a float value
425      * from the application resources.
426      * @param name the resource name
427      * @param def the default float value
428      */

429     public double getResourceFloat( String JavaDoc name, float def )
430     {
431         float ret;
432     
433     try {
434         String JavaDoc temp = bundle.getString( appClassName + "." + name );
435         // System.out.println( "temp:" + temp );
436
ret = (temp != null) ? Float.valueOf( temp.trim() ).floatValue() : def;
437         
438     }
439     catch (MissingResourceException JavaDoc e) { ret = def; }
440     return (ret);
441     }
442
443     /** This is convenience helper to get the a double value
444      * from the application resources.
445      * @param name the resource name
446      * @param def the default double value
447      */

448     public double getResourceDouble( String JavaDoc name, double def )
449     {
450         double ret;
451     
452     try {
453         String JavaDoc temp = bundle.getString( appClassName + "." + name );
454         // System.out.println( "temp:" + temp );
455
ret = (temp != null) ? Double.valueOf( temp.trim() ).doubleValue() : def;
456         
457     }
458     catch (MissingResourceException JavaDoc e) { ret = def; }
459     return (ret);
460     }
461
462     /** Substitute String
463      * For an input string s1, find the matching substring s2 in s1
464      * if the s2 can be found in s1 replace the FIRST section that
465      * matches in s1 with the replacement substring s3
466      * Return the result string.
467      */

468     public String JavaDoc substituteString( String JavaDoc input_string,
469                     String JavaDoc match_string, String JavaDoc replace_string )
470     {
471     String JavaDoc result = input_string;
472     
473     int pos = input_string.indexOf( match_string );
474     if ( pos >= 0 ) {
475         int len = match_string.length();
476         String JavaDoc left = "", right = "";
477         if (pos > 1)
478         left = input_string.substring( 0, pos );
479         if (pos < input_string.length() - len - 1)
480         right = input_string.substring( pos+len );
481         
482         result = new String JavaDoc( left + replace_string + right );
483     }
484
485     return result;
486     }
487
488     /** Replaces a set of token in the path string with matching
489         sub-strings defined in an array of substitution records */

490     public String JavaDoc replaceTokens( String JavaDoc path, SubstitutionRecord[] recs )
491     {
492     int j;
493
494     for (j=0; j<recs.length; ++j) {
495         if ( recs[j].token != null && recs[j].string != null )
496         path = substituteString( path, recs[j].token, recs[j].string );
497     }
498     return (path);
499     }
500
501     /** retrieves the search path as string
502      *
503      * First looks for the value of a system property called
504      * <B>JAVAFILESEARCHPATH</B> by called System.getProperty(). If
505      * this value is null then the resource bundle is queried for
506      * bundle called <B>applicationSearchPath</B>. If this is not
507      * defined then a default search Path is used.
508      *
509      * @see #getDefaultApplicationSearchPath()
510      *
511      * @return the string search path string. */

512     public String JavaDoc getSearchPath()
513     {
514     // Get the search Path from the system property JAVAFILESEARCHPATH.
515
if (searchPath == null) {
516         searchPath = System.getProperty( "env.JAVAFILESEARCHPATH" );
517         if (searchPath == null)
518         // Get the search Path from the resource bundle.
519
searchPath =
520             getResourceString( "applicationSearchPath",
521                        getDefaultApplicationSearchPath() );
522         if (debug)
523         System.out.println("*DEBUG* " + getClass().getName() +
524                    ".getSearchPath() searchPath=`" + searchPath + "'" );
525     }
526     return (searchPath);
527     }
528     
529
530     /*
531      * Is the string a URL resource specificer or not?
532      *
533      * <PRE>
534      * `http://lwn.net/index.html'
535      * +++ +
536      * ^ ^
537      * | |
538      * idx1 idx2
539      *
540      * return true only if idx1 < idx2 and idx1>0 and idx2>2
541      *
542      * @param url_string the URL
543      */

544     public boolean isURL( String JavaDoc url_string )
545     {
546     int idx1=-1, idx2=-1;
547     idx1 = url_string.indexOf("://");
548     if ( idx1 < 1 )
549         return (false);
550     if ( idx1 > url_string.length() + 3 )
551         idx2 = url_string.indexOf("/", idx1 + 3 );
552     // System.out.println( "idx1:" + idx1 + " idx2:" + idx2 + " output:" + (idx1 < idx2 ? "true" : "false") ); // DEBUG:
553

554     return (idx1 < idx2);
555     }
556     
557     /**
558      * Resolves a pathname to a local file or Universal Resource Locator
559      * (URL). The pathname to resolved by searching for the resource
560      * using the system property <B>env.JAVAFILESEARCHPATH</B> if defined or
561      * default search path will be used.
562      *
563      * The method breaks up the search paths in to separate pathname
564      * chunks and iterates over each one applying the following:
565      *
566      * <OL>
567      * <LI> try to load the pathname as a local file.
568      * <LI> if the pathname is a URL specification try to
569      * load as it a URL.
570      * <LI> try to load the pathname using the class loader because
571      * it may be part of a ZIP or JAR file.
572      * </OL>
573      *
574      * If the pathname can be loaded, then the iteration stops and the
575      * pathname is thus resolved. Otherwise if the iteration completes
576      * with no pathname being found whatsoever then the method returns
577      * a null object.
578      *
579      * @param type specifies the type of resource e.g. "images"
580      * @param filename specifies the name of the resource e.g. "ukmap"
581      * @param suffix specifies the suffix of the resource e.g. ".gif"
582      *
583      *
584      * @return a string representation of the resource type.
585      *
586      * Retrieval depends on the search path @see #getSearchPath
587      * and perhaps @see #getDefaultSearchPath.
588      *
589      * %P specifies the installed root the application (PREFIX).
590      * Also sets the system property `PREFIX'
591      * %B specifies the installed root the application (EXEC_PREFIX).
592      * Also sets the system property `EXEC_PREFIX'
593      * %H specifies the users directory (HOME).
594      * %A specifies the audio file directory.
595      * Also sets the system property `AUDIO_DIR'
596      * %I specifies the graphics images file directory.
597      * Also sets the system property `IMAGES_DIR'
598      * %T specifies the type (as above)
599      * %N specifies the name (as above)
600      * %S specifies the suffix (as above)
601      * %Z specifies the webroot (an internet URL).
602      * Also sets the system property `WEB_ROOT_URL'
603      *
604      * For internationalisation (i18n)
605      * %L specifies the Locale string e.g `en_uk'.
606      * %l specifies the Locale language string e.g `en'.
607      * %t specifies the Locale country string e.g `uk'.
608      * %v specifies the Locale variant string e.g. `Traditional_Win'.
609      * */

610     public String JavaDoc resolvePathname( String JavaDoc type, String JavaDoc filename, String JavaDoc suffix )
611     {
612     // Sanitise this to prevent null pointer exceptions
613
if (type == null) type="";
614     if (filename == null) filename="";
615     if (suffix == null) suffix="";
616     
617     // Perform some string token substitutions on the search path
618
SubstitutionRecord subs[] = new SubstitutionRecord[15];
619     int k;
620     for (k=0; k<subs.length; ++k) subs[k] = new SubstitutionRecord();
621
622     // Get the search path
623
getSearchPath();
624     
625     // Prefix Installed Root Dir
626
k=0;
627     subs[k].token = "%P"; subs[k].string = prefix ; ++k;
628
629     // Prefix Installed Binary Dir
630
subs[k].token = "%B"; subs[k].string = execPrefix ; ++k;
631
632     // Home directory
633
subs[k].token = "%H"; subs[k].string = System.getProperty("user.home") ; ++k;
634
635     // Substitute tilde symbol "~" for the home directory.
636
subs[k].token = "~"; subs[k].string = System.getProperty("user.home") ; ++k;
637
638     // Prefix Installed Audio Dir
639
subs[k].token = "%A"; subs[k].string = audioDir ; ++k;
640
641     // Prefix Installed Images Dir
642
subs[k].token = "%I"; subs[k].string = imagesDir ; ++k;
643
644     // Fill in Type of resource ie `images | audio | jpeg ' etc
645
subs[k].token = "%T"; subs[k].string = type ; ++k;
646
647     // Fill in the filename without suffix extension
648
subs[k].token = "%N"; subs[k].string = filename ; ++k;
649
650     // Fill in the suffix extension with `.' character
651
subs[k].token = "%S"; subs[k].string = suffix ; ++k;
652     
653     // Fill in the web page root
654
subs[k].token = "%Z"; subs[k].string = webRootURL ; ++k;
655     
656     // Set up internationalisation
657
String JavaDoc language = Locale.getDefault().getLanguage();
658     String JavaDoc country = Locale.getDefault().getCountry();
659     String JavaDoc variant = Locale.getDefault().getVariant();
660
661     String JavaDoc temp = language;
662     if ( country.length() > 0 )
663         temp += "_" + country;
664     if ( variant.length() > 0 )
665         temp += "_" + variant;
666
667     subs[k].token = "%L"; subs[k].string = temp ; ++k;
668     subs[k].token = "%l"; subs[k].string = language; ++k;
669     subs[k].token = "%t"; subs[k].string = country ; ++k;
670     subs[k].token = "%v"; subs[k].string = variant ; ++k;
671
672     if (debug) {
673         System.out.println(getClass().getName() + ".resolvePathname(...)" );
674         System.out.println(" type=`" + type + "'" );
675         System.out.println(" filename=`" + filename + "'" );
676         System.out.println(" suffix=`" + suffix + "'" );
677         System.out.println(" final language %L = `"+ temp +"'" );
678         System.out.println(" i18n language=`"+language+"' country=`"+country+
679                    "' variant=`"+variant+"'" );
680     }
681     
682     // Now break the string into components.
683
boolean bfDone = false;
684     StringTokenizer JavaDoc st = new StringTokenizer JavaDoc( searchPath, " ;\t\n");
685     String JavaDoc filePath,returnPath = null;
686     
687     while ( st.hasMoreTokens() && !bfDone ) {
688         // Get the next pathname from the pathname list
689
filePath = st.nextToken();
690
691         //
692
// Perform substitution of tokens with substring parts now
693
//
694
if (debug) System.out.println("filePath=`" + filePath + "'\t *BEFORE* substitutions" );
695         filePath = replaceTokens( filePath, subs );
696         if (debug) System.out.print("filePath=`" + filePath + "'\t *AFTER* substitutions ... " );
697
698         //
699
// See if we can read this a local file.
700
//
701
String JavaDoc tmp = normalizePathname( filePath );
702         File file = new File( tmp );
703         if ( file.exists() && file.canRead() ) {
704         // *** FOUND ***
705
if (debug) System.out.println("*FOUND FILE*");
706         returnPath = tmp;
707         bfDone = true;
708         }
709         else if ( isURL(filePath) ) {
710         // if not see we can read this a internet file.
711
try {
712             // Try to build the filePath as an URL specification.
713
URL url = new URL( filePath );
714             try {
715             // Try creating a socket which connects to the
716
// int port = (url.getPort() == -1) ? 80: url.getPort();
717
// Socket s = new Socket( url.getHost, port );
718
InputStream is = url.openStream();
719             if (debug) System.out.println("*FOUND URL*");
720             returnPath = filePath;
721             bfDone = true;
722             is.close();
723             }
724             catch (IOException ioe ) { ; }
725             
726         }
727         catch ( MalformedURLException mue) { ; }
728         }
729         else {
730         //
731
// Well that didn't work
732
//
733
// Try to opening the resource as as CLASSPATH specification.
734
// e.g. It may be part of a JAR or ZIP file.
735
// `systemresource:/ZIP0/+/docs/Author.html'
736
// `systemresource:/ZIP0/+/obi/wan/Kenobi.class'
737
// `systemresource:/FILE1/+/obi/wan/Kenobi.class'
738
//
739
// We should also try to load the application resource via the
740
// application's classloader just in case it is custom one.
741
// For example `FreeInstaller' has a self extracting classloader
742
// and custom URLStreamHandler protocol
743
// `extractor:/ZIP0/+/docs/image/duke.gif'
744
// `extractor:/FILE1/+/obi/wan/Kenobi.class'
745
// Peter Pilgrim Thu Mar 11 14:58:24 BST 1999
746
//
747
URL url = getClass().getClassLoader().getSystemResource( filePath );
748         if (url != null) {
749             try {
750             // Try creating a socket which connects to the URL
751
InputStream is = url.openStream();
752             returnPath = url.toExternalForm();
753             if (debug)
754                 System.out.println("*FOUND RESOURCE URL*\n"+ "exported url: "+returnPath );
755             bfDone = true;
756             is.close();
757             }
758             catch (IOException ioe ) { ; }
759         }
760         }
761
762         if (debug) System.out.println("");
763     }
764
765     // Return the found path to the caller
766
return (returnPath);
767     }
768
769     /** retrieves the image (GIF/JPEG) data from URL.
770      * implements performs URL.
771      *
772      * @param url_image the image URL string
773      */

774     protected byte[] getImageData( String JavaDoc url_image )
775     {
776     byte[] imageBytes=null;
777     if (debug) System.out.println( "getImageData("+url_image+")" );
778     
779     //
780
// First try reading the resource as a system file.
781
//
782
InputStream imageStream=null; // Reset this
783
String JavaDoc tmp = normalizePathname( url_image );
784     File imageFile = new File(tmp);
785     if ( imageFile.exists() && imageFile.canRead() ) {
786         try {
787         imageStream = new FileInputStream( tmp );
788         }
789         catch ( FileNotFoundException fe ) {
790         imageStream = null;
791         }
792     }
793     
794     if (imageStream == null) {
795         //
796
// Well that didn't work
797
// Second, Try to opening the resource as an URL specification.
798
//
799
try {
800         URL url = new URL( url_image );
801         // Try creating a socket which connects to the
802
// int port = (url.getPort() == -1) ? 80: url.getPort();
803
// Socket s = new Socket( url.getHost, port );
804
imageStream = url.openStream();
805         if (debug) System.out.println("*opening stream URL*");
806         }
807         catch (IOException ioe ) {
808         imageStream = null;
809         }
810     }
811     
812     if (imageStream == null) {
813         //
814
// Well that didn't work
815
//
816
// Third, Try to opening the resource as as CLASSPATH specification.
817
// e.g. It may be part of JAR or ZIP
818
imageStream = getClass().getClassLoader().getSystemResourceAsStream(url_image);
819     }
820     
821     Image JavaDoc img = null;
822     if (debug)
823         System.out.println("imageStream:" +
824                    ((imageStream==null) ?"NULL!!":"EXISTS") );
825     if ( imageStream != null ) {
826         ByteArrayOutputStream baos = new ByteArrayOutputStream();
827         
828         try {
829         // imageBytes = new byte[imageStream.available()];
830
// imageStream.read(imageBytes);
831
byte [] buffer = new byte[8192];
832         BufferedInputStream bis = new BufferedInputStream( imageStream );
833         int total_bytes=0;
834         int num_bytes;
835         while ( (num_bytes = bis.read( buffer )) > 0 ) {
836             baos.write( buffer, 0, num_bytes );
837             total_bytes += num_bytes;
838         }
839         imageBytes = baos.toByteArray();
840         // System.out.println("********** image read total "+total_bytes+" bytes." );
841
}
842         catch (IOException ex) {
843         System.err.println( getClass().getName()+".getImageData: failed to load image from URL: " + url_image );
844         }
845         finally {
846         try { imageStream.close(); } catch (IOException e) { ; }
847         }
848     }
849     
850     if (debug && imageBytes != null)
851         System.out.println( "imageBytes.length = "+imageBytes.length+" byte(s)");
852
853     return (imageBytes);
854     }
855     
856     /**
857      * Retrieves an image from application resources search path.
858      * A cache list is stores a table previously loaded images.
859      *
860      * If the image can be found in the cache by filename and
861      * suffix, then the requested image data is returned.
862      *
863      * If the image is <I>not</I> in the cache list, then search for
864      * the image from application resources search path.
865      * If the image is found it is then read from the URL
866      * and an image data created. This is stored in cache
867      * table of images.
868      *
869      * <B>NOTE:</B> If the image cannot be found then a default
870      * image is used. The image is international danger sign
871      * 24 pixel by 24 pixels.
872      *
873      *
874      * @see #resolvePathname
875      * @see #uninstallImage
876      *
877      * @param type specifies the type of resource e.g. "images"
878      * @param filename specifies the name of the resource e.g. "ukmap"
879      * @param suffix specifies the suffix of the resource e.g. ".gif"
880      *
881      * @return a string representation of the resource type.
882      */

883     public Image JavaDoc getImage( String JavaDoc type, String JavaDoc filename, String JavaDoc suffix )
884     {
885     // Create the image cache, if not done already
886
createImageCache();
887     
888     byte[] imageBytes=null;
889     String JavaDoc imagePath;
890     
891     // Sanity check
892
if (( filename == null && suffix == null ) ||
893         ( filename.length() < 1 && suffix.length() < 1 ))
894         throw new IllegalArgumentException JavaDoc( "must supply filename and/or suffix" );
895         
896     //
897
// Build a special key to retrive the image from the cache
898
//
899
String JavaDoc imageStoreKey = "";
900     // if ( type != null) imageStoreKey = type + "/";
901
if ( filename != null) imageStoreKey += filename;
902     if ( suffix != null) imageStoreKey += suffix;
903
904     Image JavaDoc cached_image = (Image JavaDoc)imageCache.get( imageStoreKey );
905     if (cached_image != null) {
906         if (debug) System.out.println( "retrieve image from *CACHE* # key:"+imageStoreKey+" cached_image:"+cached_image );
907         // Image was found in the cache return it
908
return (cached_image);
909     }
910
911     imagePath = resolvePathname( type, filename, suffix );
912     if (debug) System.out.println( "(1) imagePath=`" +imagePath+ "'" );
913     if (imagePath != null) {
914         // We manage to resolve the pathname, now try to load to
915
// retrieve it by URL!!
916
imageBytes = getImageData( imagePath );
917     }
918     else {
919         // Try loading the resource using the java language
920
// ClassLoader mechanism.
921
// Try to build the filePath as an URL specification.
922
URL url;
923         imagePath = (type == null) ?
924         filename : type + "/" + filename;
925         if (suffix != null)
926         imagePath = imagePath + "." + suffix;
927         url = ClassLoader.getSystemResource( imagePath );
928         if (url == null) {
929         // No luck, try once more with the resource name
930
// constructed without the `type'!!
931
imagePath = filename;
932         if (suffix != null)
933             imagePath = imagePath + "." + suffix;
934         url = ClassLoader.getSystemResource( imagePath );
935         }
936
937         if (debug) System.out.println( "(2) imagePath="+imagePath);
938         
939         // If url is not null then we have a resource therefore
940
// try to open the stream.
941
if (url != null) {
942         try {
943             InputStream is = url.openStream();
944             if (debug) System.out.println("*FOUND URL*");
945             // DEBUG: System.out.println( "url.toExternalForm=`" + url.toExternalForm() +"'" );
946
// Close the stream read the image bytes.
947
is.close();
948             imageBytes = getImageData( imagePath );
949             if (debug) System.out.println( "(3) imagePath="+imagePath );
950         }
951         catch (IOException ioe ) { ; }
952         }
953     }
954
955     Image JavaDoc img = null;
956     if ( imageBytes !=null && imageBytes.length > 0 ) {
957         // create image only if we got data.
958
img = Toolkit.getDefaultToolkit().createImage(imageBytes);
959
960         if (img != null) {
961         //
962
// Store newly created image in the internal cache
963
//
964
if (debug) System.out.println( "store image in cache # key:"+imageStoreKey );
965         imageCache.put( imageStoreKey, img );
966         }
967     }
968
969     if (img == null) {
970         // If we still have no image, then the use default image.
971
System.err.println("*WARNING*: Sorry, image:`" + imageStoreKey +
972                    "' cannot be found, using a default image instead.");
973         img = imageDefault;
974     }
975     
976     if (debug) System.out.println("*FINAL* getImage() img="+img);
977     return (img);
978     }
979
980     /**
981      * Removes the image name from the stored of cached images.
982      *
983      * @param imageName specifies the image name
984      */

985     public void uninstallImage( String JavaDoc imageName )
986     {
987     // Create the image cache, if not done already
988
createImageCache();
989     
990     // Remove the image from the cache, by putting null is its place.
991
Image JavaDoc cached_image = (Image JavaDoc)imageCache.get( imageName );
992     if (cached_image != null) {
993         if (debug)
994         System.out.println("*FINAL* uninstallImage(" + imageName+
995                    ") img="+cached_image);
996         imageCache.put( imageName, null );
997     }
998     }
999     
1000    /** create internal image cache */
1001    protected void createImageCache()
1002    {
1003    if ( imageCache == null) {
1004        // Make sure the image map cache is available.
1005
if (debug) System.out.println( "creating image cache now." );
1006        imageCache = new Hashtable JavaDoc();
1007    }
1008
1009    createDefaultImage();
1010    }
1011
1012    /** create default image */
1013    protected void createDefaultImage()
1014    {
1015    if ( imageDefault == null) {
1016        // Make sure the image map cache is available.
1017
if (debug) System.out.println( "create default image now." );
1018
1019        // create image only if we got data.
1020
imageDefault = Toolkit.getDefaultToolkit().createImage(DEFAULT_IMAGE_DATA);
1021        if (imageDefault != null) {
1022        //
1023
// Store newly created image in the internal cache
1024
//
1025
if (debug) System.out.println( "store image in cache # key:" + DEFAULT_IMAGE_NAME );
1026        imageCache.put( DEFAULT_IMAGE_NAME, imageDefault );
1027        }
1028    }
1029    }
1030
1031    /** Gets a font property from the resource bundle
1032     * @param name the resource name for the font property.
1033     */

1034    public Font JavaDoc getFont( String JavaDoc name )
1035    {
1036    return Font.getFont( appClassName+"."+name );
1037    }
1038
1039    /** Gets a font property from the resource bundle
1040     * @param name the resource name for the font property.
1041     * @param def the default font, if the property cannot be found.
1042     */

1043    public Font JavaDoc getFont( String JavaDoc name, Font JavaDoc def )
1044    {
1045    return Font.getFont( appClassName+"."+name, def );
1046    }
1047
1048    /** Gets a color property from the resource bundle
1049     * @param name the resource name for the color property.
1050     */

1051    public Color JavaDoc getColor( String JavaDoc name )
1052    {
1053    return Color.getColor( appClassName+"."+name );
1054    }
1055
1056    /** Gets a color property from the resource bundle
1057     * @param name the resource name for the color property.
1058     * @param def the default color, if the property cannot be found.
1059     */

1060    public Color JavaDoc getColor( String JavaDoc name, Color JavaDoc def )
1061    {
1062    return Color.getColor( appClassName+"."+name, def );
1063    }
1064
1065    /** Substitution Record nested classes for key token substitution */
1066    public class SubstitutionRecord {
1067    String JavaDoc token=null, string=null;
1068    
1069    /** Default Constructor */
1070    public SubstitutionRecord() { }
1071
1072    /** A simple constructor */
1073    public SubstitutionRecord( String JavaDoc token, String JavaDoc string )
1074    {
1075        this.token = token;
1076        this.string = string;
1077    }
1078    }
1079    
1080    /** Converts a unix pathname string to a NT/DOS string by substituting the
1081     * forward slashes (/) with backward slashes (\).
1082     * @param unixpath the unix pathname
1083     * @return the NT/DOS pathname
1084     */

1085    public static String JavaDoc convertUnixPathToNTPath( String JavaDoc unixpath )
1086    {
1087    StringBuffer JavaDoc ntpath = new StringBuffer JavaDoc();
1088
1089    for (int j=0; j<unixpath.length(); ++j) {
1090        char ch = unixpath.charAt(j);
1091        if (ch == '/' )
1092        ch = '\\';
1093        ntpath.append(ch);
1094    }
1095
1096    return ntpath.toString();
1097    }
1098    
1099
1100    /** Converts a unix pathname string to a NT/DOS string by substituting the
1101     * backward slashes (\) with forward slashes (/).
1102     * @param ntpath the NT/DOS pathname
1103     * @return the unix pathname
1104     */

1105    public static String JavaDoc convertNTPathToUnixPath( String JavaDoc ntpath )
1106    {
1107    StringBuffer JavaDoc unixpath = new StringBuffer JavaDoc();
1108
1109    for (int j=0; j<ntpath.length(); ++j) {
1110        char ch = ntpath.charAt(j);
1111        if (ch == '\\' )
1112        ch = '/';
1113        unixpath.append(ch);
1114    }
1115
1116    return unixpath.toString();
1117    }
1118    
1119
1120    /** Normalize a given pathname by convert a unix pathname string
1121     * to a NT/DOS string by substituting the forward slashes (/) with
1122     * backward slashes (\), or by converting a unix pathname string
1123     * to a NT/DOS string by substituting the backward slashes (\)
1124     * with forward slashes (/).
1125     *
1126     * @see #convertUnixPathToNTPath
1127     * @see #convertNTPathToUnixPath
1128     *
1129     * @param pathname the input pathname
1130     * @return the normalized pathname
1131     */

1132    public static String JavaDoc normalizePathname( String JavaDoc pathname )
1133    {
1134    String JavaDoc fileSep = System.getProperty("file.separator");
1135    if ( fileSep.equals("/") )
1136        return convertNTPathToUnixPath( pathname );
1137    else if ( fileSep.equals("\\") )
1138        return convertUnixPathToNTPath( pathname );
1139
1140    return (pathname);
1141    }
1142}
1143
1144// fini
1145
Popular Tags