View Javadoc

1   /*
2   Copyright (C) 2000 - 2007 Grid Systems, S.A.
3   
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License, version 2, as
6   published by the Free Software Foundation.
7   
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12  
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  */
17  
18  package com.gridsystems.utils;
19  
20  import java.io.File;
21  import java.io.FileNotFoundException;
22  import java.io.FileOutputStream;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.util.HashMap;
26  import java.util.Map;
27  import java.util.Properties;
28  import java.util.regex.Pattern;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  
33  /**
34   * General Utilities for several modules.
35   *
36   * @author Xmas
37   * @version 1.0
38   */
39  public final class SystemUtils {
40  
41    //Platform names
42    /** Windows x86. */
43    public static final String WINDOWS_X86 = "Windows_NT+x86";
44    /** Windows IA64. */
45    public static final String WINDOWS_IA64 = "Windows_NT+ia64";
46    /** SunOS sparc. */
47    public static final String SUNOS_SPARC = "SunOS+sparc";
48    /** SunOS i386. */
49    public static final String SUNOS_I386 = "SunOS+i386";
50    /** Linux i686. */
51    public static final String LINUX_I686 = "Linux+i686";
52    /** Linux IA64. */
53    public static final String LINUX_IA64 = "Linux+ia64";
54    /** Linux AMD64. */
55    public static final String LINUX_AMD64 = "Linux+x86_64";
56    /** HPUX PARISC. */
57    public static final String HPUX_PA = "HP-UX+hppa2.0w";
58    /** HPUX IA64. */
59    public static final String HPUX_IA64 = "HP-UX+ia64";
60    /** AIX PowerPC. */
61    public static final String AIX_POWERPC = "AIX+powerpc";
62    /** MacOSX PowerPC. */
63    public static final String MACOSX_POWERPC = "Darwin+powerpc";
64    /** MacOSX Intel. */
65    public static final String MACOSX_I386 = "Darwin+i386";
66  
67  
68  
69    /**
70     * Internal GridSystems Platform.
71     */
72    static OsMapEntry internalEntry;
73  
74    /**
75     * Internal Normalized OS Name.
76     */
77    private static String osName;
78  
79    /**
80     * Logger instance for this class.
81     */
82    private static Log log = LogFactory.getLog(SystemUtils.class);
83  
84    /**
85     * Platform normalization mapping.
86     */
87    static final Map<String, OsMapEntry> MAP = new HashMap<String, OsMapEntry>();
88  
89    /**
90     * OsMapEntry type.
91     */
92    static class OsMapEntry {
93      /** Entry name. */
94      private final String name;
95      /** OS recognition pattern. */
96      private final Pattern pattern;
97      /** Prefix/Suffix for native shared libraries. */
98      private final String[] libPreSuffix;
99      /** CPU architecture mappings. */
100     private final Map<String, String> archs = new HashMap<String, String>();
101 
102     /**
103      * Creates a new instance.
104      *
105      * @param key   The key
106      * @param value The value to be parsed
107      */
108     public OsMapEntry(String key, String value) {
109       this.name = key;
110       String[] tokens = value.split("\\s*,\\s*");
111       int pos = 0;
112       this.pattern = Pattern.compile(tokens[pos++]);
113       this.libPreSuffix = new String[] { tokens[pos++], tokens[pos++] };
114 
115       for (int i = pos; i < tokens.length; i++) {
116         String[] pair = tokens[i].split("\\s*=\\s*");
117         this.archs.put(pair[0], pair[1]);
118       }
119     }
120 
121     /**
122      * Gets if the specified string matches this entry pattern.
123      *
124      * @param s A platform name to process
125      * @return true if it matches
126      */
127     public boolean matches(String s) {
128       return this.pattern.matcher(s).matches();
129     }
130 
131     /**
132      * Gets the entry name.
133      *
134      * @return The entry name
135      */
136     public String getName() {
137       return this.name;
138     }
139 
140     /**
141      * Maps the specified CPU architecture.
142      *
143      * @param s The native CPU architecture
144      * @return The normalized CPU architecture
145      */
146     public String mapArch(String s) {
147       String mapped = archs.get(s);
148       return (mapped == null) ? s : mapped;
149     }
150 
151     /**
152      * Gets the prefix and suffix used for shared libraries.
153      *
154      * @return An array containing the pair [prefix, suffix]
155      */
156     public String[] getLibPreSuffix() {
157       return this.libPreSuffix;
158     }
159   }
160 
161   /**
162    * Initialise static attributes.
163    */
164   static {
165 
166     // Default OS Mappings
167     register("Windows_NT", "^Windows.*, lib,.dll, ia64=IA64");
168     register("SunOS", "^SunOS.*, lib,.so, x86=i386");
169     register("Linux", "^Linux.*, lib,.so, i386=i686,amd64=x86_64");
170     register("AIX", "^AIX.*, lib,.so");
171     register("HP-UX", "^HP-UX.*, lib,.sl, PA_RISC2.0=hppa2.0w,IA64N=ia64");
172     register("Darwin", "^Mac OS X.*, lib,.jnilib, ppc=powerpc");
173 
174     // Custom OS Mappings
175     InputStream is;
176     try {
177       ClassLoader cl = Thread.currentThread().getContextClassLoader();
178       is = cl.getResourceAsStream("os-map.properties");
179       if (is != null) {
180         Properties props = new Properties();
181         props.load(is);
182         is.close();
183 
184         for (Object obj : props.keySet()) {
185           String key = (String)obj;
186           String value = props.getProperty(key);
187           register(new OsMapEntry(key, value));
188         }
189       }
190     } catch (Exception ignore) { }
191   }
192 
193   /**
194    * Registers an entry.
195    *
196    * @param entry The entry to register
197    */
198   private static void register(OsMapEntry entry) {
199     MAP.put(entry.name, entry);
200   }
201 
202   /**
203    * Registers an entry from a [key, value] pair.
204    *
205    * @param key   The entry key
206    * @param value The entry value
207    */
208   private static void register(String key, String value) {
209     try {
210       register(new OsMapEntry(key, value));
211       log.debug("Registered OS Map " + key);
212     } catch (Exception ignore) {
213     }
214   }
215 
216   /**
217    * Private Constructor. No need to instantiate this class
218    */
219   private SystemUtils() {
220   }
221 
222 
223   /**
224    * Return true if this OS is windows.
225    *
226    * @return true if this operating system is Windows
227    */
228   public static boolean isWindows() {
229     OsMapEntry entry = getInternalEntry();
230     return entry != null && "Windows_NT".equals(entry.getName());
231   }
232 
233   /**
234    * Return true if this OS is not windows.
235    *
236    * @return true if this operating system is not Windows
237    */
238   public static boolean isUnix() {
239     OsMapEntry entry = getInternalEntry();
240     return entry != null && !"Windows_NT".equals(entry.getName());
241   }
242 
243   /**
244    * Gets the gridSystems platform name of this machine.
245    *
246    * @return A "normalized" name for this operating system
247    */
248   public static String getOsName() {
249     if (osName == null) {
250       String osId = System.getProperty("os.name");
251       String arch = System.getProperty("os.arch");
252       osName = getOsName(osId, arch);
253     }
254     return osName;
255   }
256 
257   /**
258    * Gets the local OS name without the CPU architecture.
259    *
260    * @return The OS Name
261    */
262   public static String getSimpleOsName() {
263     return getInternalEntry().getName();
264   }
265 
266   /**
267    * Gets the local architecture name.
268    *
269    * @return The Architecture name
270    */
271   public static String getSimpleArchName() {
272     String osArch = System.getProperty("os.arch");
273     return getInternalEntry().mapArch(osArch);
274   }
275 
276   /**
277    * Extracts the simple OS name from the specified platform id.
278    *
279    * @param osName The platform id
280    * @return The stripped OS name
281    */
282   public static String getSimpleOsName(String osName) {
283     int pos = osName.indexOf('+');
284     while (pos != -1) {
285       String osPrefix = osName.substring(0, pos);
286       OsMapEntry entry = getEntry(osPrefix);
287       if (entry == null) {
288         pos = osName.indexOf('+', pos + 1);
289       } else {
290         return entry.getName();
291       }
292     }
293 
294     return osName;
295   }
296 
297   /**
298    * Gets the GridSystems platform name for a machine with the passed properties.
299    *
300    * @param osName  A value for the "os.name" system property
301    * @param osArch  A value for the "os.arch" system property
302    * @return A platform name
303    */
304   public static String getOsName(String osName, String osArch) {
305     OsMapEntry entry = getEntry(osName);
306     if (entry == null) {
307       log.debug("No entry found for [" + osName + "]. OS name not normalized");
308       return osName + "+" + osArch;
309     } else {
310       return entry.name + "+" + entry.mapArch(osArch);
311     }
312   }
313 
314   /**
315    * Gets the internal OS Map Entry.
316    *
317    * @return The internal entry
318    */
319   static OsMapEntry getInternalEntry() {
320     if (internalEntry == null) {
321       String osId = System.getProperty("os.name");
322       internalEntry = getEntry(osId);
323     }
324     return internalEntry;
325   }
326 
327   /**
328    * Gets a GridSystems platform for the specified properties.
329    *
330    * @param osName  A value for the "os.name" system property
331    * @return A platform entry, or null
332    */
333   protected static OsMapEntry getEntry(String osName) {
334     for (OsMapEntry entry : MAP.values()) {
335       if (entry.matches(osName)) {
336         return entry;
337       }
338     }
339     return null;
340   }
341 
342   /**
343    * @return Gets OS version.
344    */
345   public static String getOSVersion() {
346     return System.getProperty("os.version");
347   }
348 
349   /**
350    * Retrieves the environment variables list from the system.
351    *
352    * @return The environment or an empty instance if an error occurs
353    */
354   public static Properties getEnvironment() {
355     Map<String, String> envi = System.getenv();
356     Properties env = new Properties();
357     env.putAll(envi);
358     return env;
359 
360   }
361 
362   /**
363    * Extracts a Dynamic library of a jar file and load into memory.
364    * @param dynamiclibraryname the DL name
365    * @param pathclass the path class
366    * @return Path to file extracted.
367    * @throws Exception if error
368    * @deprecated Use JNIUtils.extractDynamicLibrary method.
369    */
370   public static File extractDynamicLibrary(String dynamiclibraryname,
371                                     Class< ? > pathclass) throws Exception {
372     return JNIUtils.extractDynamicLibrary(dynamiclibraryname, pathclass);
373   }
374 
375   /**
376    * Extracts a Dynamic library of a jar file and loads it into memory.
377    * @param dynamiclibraryname the DL name
378    * @param path the path
379    * @return Path to file extracted.
380    * @throws Exception if error
381    *  @deprecated Use JNIUtils.extractDynamicLibrary method.
382    */
383   public static File extractDynamicLibrary(
384     String dynamiclibraryname, String path) throws Exception {
385     return JNIUtils.extractDynamicLibrary(dynamiclibraryname, path);
386   }
387 
388   /**
389    * @return the temporal system directory
390    */
391   public static String getTempDir() {
392     String tmpdir = System.getProperty("java.io.tmpdir", null);
393     return ((tmpdir == null) ? System.getProperty("user.home") : tmpdir);
394   }
395 
396   /**
397    * Executes the given command and saves its output into a file.
398    * @param command the command to execute
399    * @param envp the environment
400    * @param baseDir the base directory
401    * @param output Where store StdOut and StdErr of executable
402    * @return null, if execution has failed, otherwise return Integer with exit code
403    */
404   public static Integer execAndSaveOutput(String command, String[] envp, File baseDir,
405                                       OutputStream output) {
406     String[] cmd = new String[] {command };
407     final boolean executeAsArray = false;
408     return execAndSaveOutput(cmd, envp, baseDir, output, executeAsArray);
409   }
410 
411   /**
412    * Executes the given command and saves its output into a file.
413    * @param command the command to execute
414    * @param envp the environment
415    * @param baseDir the base directory
416    * @param output Where store StdOut and StdErr of executable
417    * @return null, if execution has failed, otherwise return Integer with exit code
418    */
419   public static Integer execAndSaveOutput(String[] command, String[] envp, File baseDir,
420                                       OutputStream output) {
421     final boolean executeAsArray = true;
422     return execAndSaveOutput(command, envp, baseDir, output, executeAsArray);
423   }
424 
425   /**
426    * Executes the given command and saves its output into a file.
427    * @param command the command to execute
428    * @param envp the environment
429    * @param baseDir the base directory
430    * @param output Where store StdOut and StdErr of executable
431    * @param executeAsArray Execute as full command line, or execute command
432    *        and parameters.
433    * @return null, if execution has failed, otherwise return Integer with exit code
434    */
435   private static Integer execAndSaveOutput(String[] command, String[] envp, File baseDir,
436       OutputStream output, boolean executeAsArray) {
437     try {
438       Process p;
439       if (executeAsArray) {
440         p = Runtime.getRuntime().exec(command, envp, baseDir);
441       } else {
442         p = Runtime.getRuntime().exec(command[0], envp, baseDir);
443       }
444       SystemStream std = new SystemStream(p.getInputStream(), output);
445       SystemStream err = new SystemStream(p.getErrorStream(), output);
446       std.start();
447       err.start();
448 
449       int exit = p.waitFor();
450 
451       try {
452         std.stopThread();
453       } catch (Exception ex) {
454         log.error("Exception happened when stopping SystemStream", ex);
455       }
456       try {
457         err.stopThread();
458       } catch (Exception ex) {
459         log.error("Exception happened when stopping SystemStream", ex);
460       }
461 
462       return new Integer(exit);
463     } catch (Exception ex) {
464       log.error("Error executing command: " + command, ex);
465       return null;
466     }
467   }
468 
469   /**
470    * Executes the given command piping its input and output with System.out and System.in.
471    * @param command the command to execute
472    * @param envp the environment
473    * @param baseDir the base directory
474    * @return null, if execution has failed, otherwise return Integer with exit code
475    */
476   public static Integer execPiped(String command, String[] envp, File baseDir) {
477     final boolean executeAsArray = false;
478     String[] cmd = new String[] { command };
479     return execPiped(cmd, envp, baseDir, executeAsArray);
480   }
481 
482   /**
483    * Executes the given command piping its input and output with System.out and System.in.
484    * @param command the command to execute
485    * @param envp the environment
486    * @param baseDir the base directory
487    * @param executeAsArray Execute as full command line, or execute command
488    *        and parameters.
489    * @return null, if execution has failed, otherwise return Integer with exit code
490    */
491   private static Integer execPiped(String[] command, String[] envp, File baseDir,
492       boolean executeAsArray) {
493 
494     SystemStream[] ss = null;
495     try {
496       Process p;
497       if (executeAsArray) {
498         p = Runtime.getRuntime().exec(command, envp, baseDir);
499       } else {
500         p = Runtime.getRuntime().exec(command[0], envp, baseDir);
501       }
502       ss = new SystemStream[] {
503         new SystemStream(p.getErrorStream(), System.out),
504         new SystemStream(p.getInputStream(), System.out)
505       };
506       for (int i = 0; i < ss.length; i++) {
507         ss[i].start();
508       }
509 
510       int exit = p.waitFor();
511 
512       return new Integer(exit);
513     } catch (Exception ex) {
514       log.error("Error executing command '" + command + "'", ex);
515       return null;
516     } finally {
517       if (ss != null) {
518         for (int i = 0; i < ss.length; i++) {
519           try {
520             ss[i].stopThread();
521           } catch (Exception ex) {
522             log.error("Exception happened when stopping SystemStream(" + i + ")", ex);
523           }
524         }
525       }
526     }
527   }
528 
529   /**
530    * Executes the given command and saves its output into a file.
531    * @param command the command to execute
532    * @param envp the environment
533    * @param baseDir the base directory
534    * @param outputFile the output file
535    * @return null, if execution has failed, otherwise return Integer with exit code
536    */
537   public static Integer execAndSaveOutput(String[] command, String[] envp, File baseDir,
538                                       File outputFile) {
539     FileOutputStream output;
540     try {
541       output = new FileOutputStream(outputFile);
542       final boolean executeAsArray = true;
543       return execAndSaveOutput(command, envp, baseDir, output, executeAsArray);
544     } catch (FileNotFoundException e) {
545       log.error("Cannot create output file " + outputFile.toString());
546       return null;
547     }
548   }
549 
550   /**
551    * Executes the given command and saves its output into a file.
552    * @param command the command to execute
553    * @param envp the environment
554    * @param baseDir the base directory
555    * @param outputFile the output file
556    * @return null, if execution has failed, otherwise return Integer with exit code
557    */
558   public static Integer execAndSaveOutput(String command, String[] envp, File baseDir,
559                                       File outputFile) {
560     final boolean executeAsArray = false;
561     FileOutputStream output;
562     try {
563       output = new FileOutputStream(outputFile);
564       String[] cmd = new String[]{ command };
565       return execAndSaveOutput(cmd, envp, baseDir, output, executeAsArray);
566     } catch (FileNotFoundException e) {
567       log.error("Cannot create output file " + outputFile.toString());
568       return null;
569     }
570   }
571 
572   /**
573    * Executes the given command piping its input and output with System.out and System.in.
574    * @param command the command to execute
575    * @param envp the environment
576    * @param baseDir the base directory
577    * @return null, if execution has failed, otherwise return Integer with exit code
578    */
579   public static Integer execPiped(String[] command, String[] envp, File baseDir) {
580     final boolean executeAsArray = true;
581     return execPiped(command, envp, baseDir, executeAsArray);
582   }
583 
584   /**
585    * Nested class SystemStream is a thread that reads from an input stream and
586    * writes what has read to an output stream, ad infinitum.
587    */
588   static class SystemStream extends Thread implements Runnable {
589     /** Input stream. */
590     InputStream pi = null;
591     /** Output stream. */
592     OutputStream po = null;
593     /** Interruption flag. */
594     boolean interruptFlag = false;
595 
596     /**
597      * Creates a pipe between these two streams.
598      *
599      * @param pi the input stream
600      * @param po the output stream
601      */
602     public SystemStream(InputStream pi, OutputStream po) {
603       interruptFlag = false;
604       this.pi = pi;
605       this.po = po;
606     }
607 
608     /**
609      * Writes all incoming characters to the output stream.
610      */
611     @Override public void run() {
612       int ch;
613       try {
614         while (!interruptFlag) {
615           ch = pi.read();
616           if (ch == -1) {
617             break;
618           }
619           po.write(ch);
620           po.flush();
621         }
622       } catch (Exception e) {
623         e.printStackTrace();
624       }
625     }
626 
627     /**
628      * Thread stop method.
629      *
630      */
631     public void stopThread() {
632       this.interruptFlag = true;
633     }
634   }
635   // End of nested class SystemStream
636 
637 //  /**
638 //   * Test main method.
639 //   * @param args argument
640 //   */
641 //  public static void main(String[] args) {
642 //    if (args.length == 0) {
643 //      System.out.println("Usage: java SystemUtils GSOsName [LibName]");
644 //      System.exit(1);
645 //    }
646 //
647 //    log = new SimpleLog("SystemUtils.class");
648 //    ((SimpleLog) log).setLevel(SimpleLog.LOG_LEVEL_OFF);
649 //
650 //    String gsOsname = args[0];
651 //
652 //    if (args.length == 1) {
653 //      System.out.println(gsOsname);
654 //    } else {
655 //      String[] prepost = getNativePrefixPostfix(gsOsname);
656 //      if (prepost == null) {
657 //        System.err.print("Cannot find prefix/postfix for dynamic library of ");
658 //        System.err.println(gsOsname);
659 //        System.exit(3);
660 //      } else {
661 //        System.out.println(gsOsname + File.separator + prepost[0]
662 //                           + args[1] + prepost[1]);
663 //      }
664 //    }
665 //    System.exit(0);
666 //  }
667 }