KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > izforge > izpack > util > TargetFactory


1 /*
2  * IzPack - Copyright 2001-2007 Julien Ponge, All Rights Reserved.
3  *
4  * http://www.izforge.com/izpack/
5  * http://developer.berlios.de/projects/izpack/
6  *
7  * Copyright 2002 Elmar Grom
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */

21
22 package com.izforge.izpack.util;
23
24 import java.io.BufferedReader JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.io.InputStreamReader JavaDoc;
28 import java.util.StringTokenizer JavaDoc;
29
30 /*---------------------------------------------------------------------------*/
31 /**
32  * The <code>TargetFactory</code> serves as a central mechanism to instantiate OS specific class
33  * flavors, provide OS specific file extension types, default install directories and similar
34  * functionality. In addition it provides services that are related to OS versions and flavors. For
35  * a tutorial on using some of the features in this class see the <A
36  * HREF=doc-files/TargetFactory.html>TargetFactory Tutorial</A>.
37  *
38  * @version 0.0.1 / 1/3/2002
39  * @author Elmar Grom
40  */

41 /*---------------------------------------------------------------------------*/
42 /*
43  * $ @design
44  *
45  * Reports actually observed on some systems:
46  *
47  * OS OS Name Version Architecture Native Report (ver)
48  * ----------------------------------------------------------------------------------------------------------
49  * Windows 95 Windows 98 Windows 98 4.10 x86 Windows 98 [Version 4.10.1998] Windows-ME Windows Me
50  * 4.90 x86 Windows Millennium [Version 4.90.3000] Windows-NT 3.5 Windows-NT 4.0 Windows NT 4.0 x86
51  * Windows NT Version 4.0 Windows 2000 Windows 2000 5.0 x86 Microsoft Windows 2000 [Version
52  * 5.00.2195] Windows-XP Windows 2000 5.1 x86 Microsoft Windows XP [Version 5.1.2600] Windows-XP
53  * Windows XP 5.1 x86 Mac Mac OS-X Linux Linux 2.4.7-10 i386 Linux Linux 2.4.18-4GB i386 Solaris
54  *
55  * ---------------------------------------------------------------------------
56  */

57 public class TargetFactory
58 {
59
60     // ------------------------------------------------------------------------
61
// Constant Definitions
62
// ------------------------------------------------------------------------
63

64     // Basic operating systems
65

66     /** Identifies Microsoft Windows. */
67     public static final int WINDOWS = 0;
68
69     /** Identifies generic UNIX operating systems */
70     public static final int UNIX = 2;
71
72     /** Used to report a non specific operating system. */
73     public static final int GENERIC = 3;
74
75     // operating system favors
76

77     /** This is the basic flavor for every operating system. */
78     public static final int STANDARD = 0;
79
80     /**
81      * Used to identify the Windows-NT class of operating systems in terms of an OS flavor. It is
82      * reported for Windows-NT, 2000 and XP.
83      */

84     public static final int NT = 1;
85
86     /** Used to identify the OS X flavor of the Mac OS */
87     public static final int X = 2;
88
89     // system architecture
90

91     /** Identifies Intel X86 based processor types. */
92     public static final int X86 = 0;
93
94     /** Nonspecific processor architecture, other than X86. */
95     public static final int OTHER = 1;
96
97     /**
98      * The extensions used for native libraries on various operating systems. The string positions
99      * correspond to the basic operating system indexes. The following values are legal to use :
100      * <br>
101      * <br>
102      * <ul>
103      * <li>WINDOWS
104      * <li>MAC
105      * <li>UNIX
106      * <li>GENERIC
107      * </ul>
108      */

109     static final String JavaDoc[] LIBRARY_EXTENSION = { "dll", "so", "", ""};
110
111     /**
112      * The os specific class prefixes for classes that implement different versions for the various
113      * operating systems. The string positions correspond to the basic operating system indexes. The
114      * following values are legal to use : <br>
115      * <br>
116      * <ul>
117      * <li>WINDOWS
118      * <li>MAC
119      * <li>UNIX
120      * <li>GENERIC
121      * </ul>
122      */

123     static final String JavaDoc[] CLASS_PREFIX = { "Win_", "Mac_", "Unix_", ""};
124
125     /**
126      * The os favor specific class prefixes for classes the implement different versions for various
127      * os favors. The string positions correspond to the flavor indexes. The following values are
128      * legal to use : <br>
129      * <br>
130      * <ul>
131      * <li>STANDARD
132      * <li>NT
133      * <li>X
134      * </ul>
135      */

136     static final String JavaDoc[] CLASS_FLAVOR_PREFIX = { "", "NT_", "X_"};
137
138     /**
139      * The list of processor architecture specific prefixes. The string positions correspond to the
140      * architecture indexes. The following values are leegal to use : <br>
141      * <br>
142      * <ul>
143      * <li>X86
144      * <li>OTHER
145      * </ul>
146      */

147     static final String JavaDoc[] CLASS_ARCHITECTURE_PREFIX = { "X86_", // Intel X86
148
// architecture
149
"U_" // unknown
150
};
151
152     /**
153      * The list of default install path fragments. Depending on the operating system, a path
154      * fragment might represent either a part of the default install path or the entire path to use.
155      * For MS-Windows it is always only a part of the full install path. The string positions
156      * correspond to the basic operating system indexes. The following values are leegal to use :
157      * <br>
158      * <br>
159      * <ul>
160      * <li>WINDOWS
161      * <li>MAC
162      * <li>UNIX
163      * <li>GENERIC
164      * </ul>
165      */

166     static final String JavaDoc[] INSTALL_PATH_FRAGMENT = { "Program Files" + File.separator,
167             "/Applications" + File.separator, "/usr/local" + File.separator,
168             File.separator + "apps" + File.separator};
169
170     /**
171      * This is a list of keys to use when looking for resources that define the default install path
172      * to use. The list is organized as two dimensional array of <code>String</code>s. To access
173      * the array, denote the first dimension with the operating system index and the second
174      * dimension with the flavor index. For example to access the key for Windows-NT use
175      * <code>INSTALL_PATH_RESOURCE_KEY[WINDOWS][NT]</code> The array uses a sparse population,
176      * that is, not all array locations actually contain a key. Only locations for which a real
177      * operating system/flavor combination exists are populated. For example, there is no such thing
178      * as <code>INSTALL_PATH_RESOURCE_KEY[UNIX][X]</code>
179      */

180     static final String JavaDoc[][] INSTALL_PATH_RESOURCE_KEY = {
181     // Standard NT X
182
{ "TargetPanel.dir.windows", "TargetPanel.dir.windows", ""}, // Windows
183
{ "TargetPanel.dir.mac", "", "TargetPanel.dir.macosx"}, // Mac
184
{ "TargetPanel.dir.unix", "", ""}, // UNIX
185
{ "TargetPanel.dir", "", ""} // Generic
186
};
187
188     /** The delimiter characters used to tokenize version numbers */
189     private static final String JavaDoc VERSION_DELIMITER = ".-";
190
191     // ------------------------------------------------------------------------
192
// Variable Declarations
193
// ------------------------------------------------------------------------
194
/**
195      * The reference to the single instance of <code>TargetFactory</code>. Used in static methods
196      * in place of <code>this</code>.
197      */

198     private static TargetFactory me = null;
199
200     /** identifies the operating system we are running on */
201     private int os = -1;
202
203     /** identifies the operating system favor */
204     private int osFlavor = -1;
205
206     /** identifies the hardware architecture we are running on */
207     private int architecture = -1;
208
209     /** represents the version number of the target system */
210     private String JavaDoc version = "";
211
212     /*--------------------------------------------------------------------------*/
213     /**
214      * Constructor
215      */

216     /*--------------------------------------------------------------------------*/
217     /*
218      * $ @design
219      *
220      * Identify the following about the target system: - OS type - architecture - version
221      *
222      * and store this information for later use.
223      * --------------------------------------------------------------------------
224      */

225     private TargetFactory()
226     {
227         version = System.getProperty("os.version");
228
229         // ----------------------------------------------------
230
// test for Windows
231
// ----------------------------------------------------
232
if (OsVersion.IS_WINDOWS)
233         {
234             os = WINDOWS;
235             osFlavor = STANDARD;
236             architecture = X86;
237             String JavaDoc osName = OsVersion.OS_NAME.toLowerCase();
238
239             if (osName.indexOf("nt") > -1)
240             {
241                 osFlavor = NT;
242             }
243             else if (osName.indexOf("2000") > -1)
244             {
245                 osFlavor = NT;
246             }
247             else if (osName.indexOf("xp") > -1)
248             {
249                 osFlavor = NT;
250             }
251         }
252         // ----------------------------------------------------
253
// test for Mac OS
254
// ----------------------------------------------------
255
else if (OsVersion.IS_OSX)
256         {
257             os = X;
258             osFlavor = STANDARD;
259             architecture = OTHER;
260         }
261         // ----------------------------------------------------
262
// what's left should be unix
263
// ----------------------------------------------------
264
else
265         {
266             os = UNIX;
267             osFlavor = STANDARD;
268             architecture = OTHER;
269             String JavaDoc osName = OsVersion.OS_NAME.toLowerCase();
270
271             if (osName.indexOf("x86") > -1)
272             {
273                 architecture = X86;
274             }
275         }
276     }
277
278     /*--------------------------------------------------------------------------*/
279     /**
280      * Returns an instance of <code>TargetFactory</code> to use.
281      *
282      * @return an instance of <code>TargetFactory</code>.
283      */

284     /*--------------------------------------------------------------------------*/
285     public static TargetFactory getInstance()
286     {
287         if (me == null)
288         {
289             me = new TargetFactory();
290         }
291
292         return me;
293     }
294
295     /*--------------------------------------------------------------------------*/
296     /**
297      * This method returns an OS and OS flavor specific instance of the requested class. <br>
298      * <br>
299      * <b>Class Naming Rules</b><br>
300      * Class versions must be named with the OS and OS flavor as prefix. The prefixes are simply
301      * concatenated, with the OS prefix first and the flavor prefix second. Use the following OS
302      * specific prefixes:<br>
303      * <br>
304      * <TABLE BORDER=1>
305      * <TR>
306      * <TH>Operating System</TH>
307      * <TH>Prefix</TH>
308      * </TR>
309      * <TR>
310      * <TD>Microsoft Windows</TD>
311      * <TD>Win_</TD>
312      * </TR>
313      * <TR>
314      * <TD>Mac OS</TD>
315      * <TD>Mac_</TD>
316      * </TR>
317      * <TR>
318      * <TD>UNIX</TD>
319      * <TD>UNIX_</TD>
320      * </TR>
321      * </TABLE><br>
322      * For the different OS flavors, use these prefixes:<br>
323      * <br>
324      * <TABLE BORDER=1>
325      * <TR>
326      * <TH>OS Flavor</TH>
327      * <TH>Prefix</TH>
328      * </TR>
329      * <TR>
330      * <TD>NT</TD>
331      * <TD>NT_</TD>
332      * </TR>
333      * <TR>
334      * <TD>Mac OS X</TD>
335      * <TD>X_</TD>
336      * </TR>
337      * </TABLE> <br>
338      * <br>
339      * <b>Naming Example:</b> <br>
340      * <br>
341      * For the class <code>MyClass</code>, the specific version for Windows NT must be in the
342      * same package as <code>MyClass</code> and the name must be <code>Win_NT_MyClass</code>. A
343      * version that should be instantiated for any non-NT flavor would be called
344      * <code>Win_MyClass</code>. This would also be the version instantiated on Windows NT if the
345      * version <code>Win_NT_MyClass</code> does not exist. <br>
346      * <br>
347      * <b>The Loading Process</b> <br>
348      * <br>
349      * The process is completed after the first successful attempt to load a class. <br>
350      * <ol>
351      * <li>load a version that is OS and OS-Flavor specific
352      * <li>load a version that is OS specific
353      * <li>load the base version (without OS or OS-Flavor prefix)
354      * </ol>
355      * <br>
356      * See the <A HREF=doc-files/TargetFactory.html>TargetFactory Tutorial</A> for more
357      * information.<br>
358      * <br>
359      *
360      * @param name the fully qualified name of the class to load without the extension.
361      *
362      * @return An instance of the requested class. Note that specific initialization that can not be
363      * accomplished in the default constructor still needs to be performed before the object can be
364      * used.
365      *
366      * @exception Exception if all attempts to instantiate class fail
367      */

368     /*--------------------------------------------------------------------------*/
369     public Object JavaDoc makeObject(String JavaDoc name) throws Exception JavaDoc
370     {
371         int nameStart = name.lastIndexOf('.') + 1;
372         String JavaDoc packageName = name.substring(0, nameStart);
373         String JavaDoc className = name.substring(nameStart, name.length());
374         String JavaDoc actualName;
375
376         try
377         {
378             actualName = packageName + CLASS_PREFIX[os] + CLASS_FLAVOR_PREFIX[osFlavor] + className;
379             Class JavaDoc temp = Class.forName(actualName);
380             return temp.newInstance();
381         }
382         catch (Throwable JavaDoc exception1)
383         {
384             try
385             {
386                 Class JavaDoc temp = Class.forName(packageName + CLASS_PREFIX[os] + className);
387                 return temp.newInstance();
388             }
389             catch (Throwable JavaDoc exception2)
390             {
391                 try
392                 {
393                     actualName = name;
394                     Class JavaDoc temp = Class.forName(actualName);
395                     return temp.newInstance();
396                 }
397                 catch (Throwable JavaDoc exception3)
398                 {
399                     throw new Exception JavaDoc("can not instantiate class " + name);
400                 }
401             }
402         }
403     }
404
405     /*--------------------------------------------------------------------------*/
406     /**
407      * Returns true if the version in the parameter string is higher than the version of the target
408      * os.
409      *
410      * @param version the version number to compare to
411      *
412      * @return <code>false</code> if the version of the target system is higher, otherwise
413      * <code>true</code>
414      */

415     /*--------------------------------------------------------------------------*/
416     /*
417      * $ @design
418      *
419      * Version numbers are assumed to be constructed as follows: - a list of one or more numbers,
420      * separated by periods as in X.X.X. ... or periods and dashes as in X.X.X-Y. ... - the numbers
421      * follow the decimal number system - the left most number is of highest significance
422      *
423      * The process compares each set of numbers, beginning at the most significant and working down
424      * the ranks (this is working left to right). The process is stopped as soon as the pair of
425      * numbers compaired is not equal. If the numer for the target system is higher, flase is
426      * returned, otherwise true.
427      * --------------------------------------------------------------------------
428      */

429     public boolean versionIsHigher(String JavaDoc version) throws Exception JavaDoc
430     {
431         StringTokenizer JavaDoc targetVersion = new StringTokenizer JavaDoc(this.version, VERSION_DELIMITER);
432         StringTokenizer JavaDoc compareVersion = new StringTokenizer JavaDoc(version, VERSION_DELIMITER);
433
434         int target;
435         int compare;
436
437         while (targetVersion.hasMoreTokens() && compareVersion.hasMoreTokens())
438         {
439             try
440             {
441                 target = Integer.parseInt(targetVersion.nextToken());
442                 compare = Integer.parseInt(compareVersion.nextToken());
443             }
444             catch (Throwable JavaDoc exception)
445             {
446                 throw new Exception JavaDoc("error in version string");
447             }
448
449             if (compare > target)
450             {
451                 return true;
452             }
453             else if (target > compare) { return false; }
454         }
455
456         return false;
457     }
458
459     /*--------------------------------------------------------------------------*/
460     /**
461      * Returns the index number for the target operating system that was detected.
462      *
463      * @return an index number for the OS
464      *
465      * @see #WINDOWS
466      * @see #UNIX
467      * @see #GENERIC
468      */

469     /*--------------------------------------------------------------------------*/
470     public int getOS()
471     {
472         return os;
473     }
474
475     /*--------------------------------------------------------------------------*/
476     /**
477      * Returns the index number for the operating system flavor that was detected on the target
478      * system.
479      *
480      * @return an index for the OS flavor
481      *
482      * @see #STANDARD
483      * @see #NT
484      * @see #X
485      */

486     /*--------------------------------------------------------------------------*/
487     public int getOSFlavor()
488     {
489         return osFlavor;
490     }
491
492     /*--------------------------------------------------------------------------*/
493     /**
494      * Returns an index number that identified the processor architecture of the target system.
495      *
496      * @return an index for the processor architecture
497      *
498      * @see #X86
499      * @see #OTHER
500      */

501     /*--------------------------------------------------------------------------*/
502     public int getArchitecture()
503     {
504         return architecture;
505     }
506
507     /*--------------------------------------------------------------------------*/
508     /**
509      * Returns the file extension customarily used on the target OS for dynamically loadable
510      * libraries.
511      *
512      * @return a <code>String</code> containing the customary library extension for the target OS.
513      * Note that the string might be empty if there no such specific extension for the target OS.
514      */

515     /*--------------------------------------------------------------------------*/
516     public String JavaDoc getNativeLibraryExtension()
517     {
518         return LIBRARY_EXTENSION[os];
519     }
520
521     /*--------------------------------------------------------------------------*/
522     /**
523      * Returns the system dependent default install path. This is typically used to suggest an
524      * istall path to the end user, when performing an installation. The default install path is
525      * assembled form the OS specific path fragment specified in <code>INSTALL_PATH_FRAGMENT</code>,
526      * possibly a drive letter and the application name. The user the option to define resources
527      * that define default paths which differ from the path fragments defined here. The following
528      * resource names will be recognized by this method: <br>
529      * <br>
530      * <ul>
531      * <li><code>TargetPanel.dir.windows</code>
532      * <li><code>TargetPanel.dir.macosx</code>
533      * <li><code>TargetPanel.dir.unix</code>
534      * <li><code>TargetPanel.dir</code> plus the all lower case version of
535      * <code>System.getProperty ("os.name")</code>, with all spaces replaced by an underscore
536      * ('_').
537      * <li><code>TargetPanel.dir</code>
538      * </ul>
539      *
540      * @param appName the name of the application to install. If no specific resource has been set,
541      * then this name will be appended to the OS specific default path fragment.
542      *
543      * @return the default install path for the target system
544      */

545     /*--------------------------------------------------------------------------*/
546     /*
547      * $ @design
548      *
549      * First try to read a path string from a resource file. This approach allows the user to
550      * customize the default install path that is suggested to the end user by IzPack. There are a
551      * number of choices for the naming of this resource, so we need to go through a few steps in
552      * order to exhaust the different possibilities. If this was not successful we use the default
553      * install path that is defined for the operating system we are running on. This path should be
554      * expanded by the application name to form the full path that to returne.
555      * --------------------------------------------------------------------------
556      */

557     public String JavaDoc getDefaultInstallPath(String JavaDoc appName)
558     {
559         String JavaDoc path = null;
560         InputStream JavaDoc input;
561         String JavaDoc keyFragment = "/res/" + INSTALL_PATH_RESOURCE_KEY[GENERIC][STANDARD];
562
563         // ----------------------------------------------------
564
// attempt to get an input stream through a resource
565
// based on a key which is specific to the target OS
566
// ----------------------------------------------------
567
input = getClass().getResourceAsStream("/res/" + INSTALL_PATH_RESOURCE_KEY[os][osFlavor]);
568
569         // ----------------------------------------------------
570
// attempt to get an input stream through a resource
571
// based on a key which is made specific to the target
572
// OS by using the string returned by
573
// System.getProperty ("os.name").toLowerCase ()
574
// ----------------------------------------------------
575
if (input == null)
576         {
577             String JavaDoc key = OsVersion.OS_NAME.toLowerCase().replace(' ', '_'); // avoid
578
// spaces
579
// in
580
// file
581
// names
582
key = keyFragment + key.toLowerCase(); // for consistency among
583
// TargetPanel res files
584
input = TargetFactory.class.getResourceAsStream(key);
585         }
586
587         // ----------------------------------------------------
588
// attempt to get an input stream through a resource
589
// based on a key which is not specific to any target OS
590
// ----------------------------------------------------
591
if (input == null)
592         {
593             input = TargetFactory.class.getResourceAsStream(keyFragment);
594         }
595
596         // ----------------------------------------------------
597
// If we got an input stream try to read the path
598
// from the file
599
// ----------------------------------------------------
600
if (input != null)
601         {
602             InputStreamReader JavaDoc streamReader;
603             BufferedReader JavaDoc reader = null;
604             String JavaDoc line;
605
606             try
607             {
608                 streamReader = new InputStreamReader JavaDoc(input);
609                 reader = new BufferedReader JavaDoc(streamReader);
610                 line = reader.readLine();
611
612                 while (line != null)
613                 {
614                     line = line.trim();
615                     if (!"".equals(line))
616                     {
617                         break;
618                     }
619                     line = reader.readLine();
620                 }
621                 path = line;
622             }
623             catch (Throwable JavaDoc exception)
624             {}
625             finally
626             {
627                 try
628                 {
629                     if (reader != null) reader.close();
630                 }
631                 catch (Throwable JavaDoc exception)
632                 {}
633             }
634         }
635
636         // ----------------------------------------------------
637
// if we were unable to obtain a path from a resource,
638
// use the default for the traget operating system.
639
// ----------------------------------------------------
640
if (path == null || "".equals(path))
641         {
642             path = "";
643
644             // --------------------------------------------------
645
// if we run on windows, we need a valid drive letter
646
// to put in front of the path. The drive that
647
// contains the user's home directory is usually the
648
// drive that also contains the install directory,
649
// so this seems the best choice here.
650
// --------------------------------------------------
651
if (os == WINDOWS)
652             {
653                 String JavaDoc home = System.getProperty("user.home");
654                 // take everything up to and including the first '\'
655
path = home.substring(0, home.indexOf(File.separatorChar) + 1);
656             }
657
658             path = path + INSTALL_PATH_FRAGMENT[os] + appName;
659         }
660
661         return path;
662     }
663
664     /**
665      * Gets a prefix alias for the current platform. "Win_" on Windows Systems "Win_NT_" on WinNT4,
666      * 2000, XP Mac on Mac Mac_X on macosx and Unix_
667      *
668      * @return a prefix alias for the current platform
669      */

670
671     public static String JavaDoc getCurrentOSPrefix()
672     {
673         String JavaDoc OSName = System.getProperty("os.name").toLowerCase();
674         String JavaDoc OSArch = System.getProperty("os.arch").toLowerCase();
675         int OS = 0;
676         int OSFlavor = 0;
677         int OSarchitecture = 0;
678         // ----------------------------------------------------
679
// test for Windows
680
// ----------------------------------------------------
681
if (OSName.indexOf("windows") > -1)
682         {
683             OS = WINDOWS;
684             OSFlavor = STANDARD;
685             OSarchitecture = X86;
686
687             if (OSName.indexOf("nt") > -1)
688             {
689                 OSFlavor = NT;
690             }
691             else if (OSName.indexOf("2000") > -1)
692             {
693                 OSFlavor = NT;
694             }
695             else if (OSName.indexOf("xp") > -1)
696             {
697                 OSFlavor = NT;
698             }
699         }
700         // ----------------------------------------------------
701
// test for Mac OS
702
// ----------------------------------------------------
703
else if (OSName.indexOf("mac") > -1)
704         {
705             OS = GENERIC;
706             OSFlavor = STANDARD;
707             OSarchitecture = OTHER;
708
709             if (OSName.indexOf("macosx") > -1)
710             {
711                 OSFlavor = X;
712             }
713         }
714         // ----------------------------------------------------
715
// what's left should be unix
716
// ----------------------------------------------------
717
else
718         {
719             OS = UNIX;
720             OSFlavor = STANDARD;
721             OSarchitecture = OTHER;
722
723             if (OSArch.indexOf("86") > -1)
724             {
725                 OSarchitecture = X86;
726             }
727         }
728
729         return (CLASS_PREFIX[OS] + CLASS_FLAVOR_PREFIX[OSFlavor]);
730     }
731
732 }
733 /*---------------------------------------------------------------------------*/
734
Popular Tags