View Javadoc

1   /*
2    * $Id: SystemUtils.java 23213 2011-10-18 17:33:21Z mike.schilling $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.util;
12  
13  import org.mule.api.DefaultMuleException;
14  
15  import java.io.BufferedReader;
16  import java.io.InputStreamReader;
17  import java.lang.reflect.Method;
18  import java.util.Collections;
19  import java.util.HashMap;
20  import java.util.Map;
21  
22  import org.apache.commons.cli.BasicParser;
23  import org.apache.commons.cli.CommandLine;
24  import org.apache.commons.cli.Option;
25  import org.apache.commons.cli.Options;
26  import org.apache.commons.cli.ParseException;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  
30  // @ThreadSafe
31  
32  public class SystemUtils extends org.apache.commons.lang.SystemUtils
33  {
34      // class logger
35      protected static final Log logger = LogFactory.getLog(SystemUtils.class);
36  
37      // bash prepends: declare -x
38      // zsh prepends: typeset -x
39      private static final String[] UNIX_ENV_PREFIXES = new String[]{"declare -", "typeset -"};
40  
41      // the environment of the VM process
42      private static Map environment = null;
43  
44      /**
45       * Get the operating system environment variables. This should work for Windows
46       * and Linux.
47       *
48       * @return Map<String, String> or an empty map if there was an error.
49       */
50      public static synchronized Map getenv()
51      {
52          if (environment == null)
53          {
54              try
55              {
56                  if (SystemUtils.IS_JAVA_1_4)
57                  {
58                      // fallback to external process
59                      environment = Collections.unmodifiableMap(getenvJDK14());
60                  }
61                  else
62                  {
63                      // the following runaround is necessary since we still want to
64                      // compile on JDK 1.4
65                      Class target = System.class;
66                      Method envMethod = target.getMethod("getenv", ArrayUtils.EMPTY_CLASS_ARRAY);
67                      environment = Collections.unmodifiableMap((Map) envMethod.invoke(target, (Object[]) null));
68                  }
69              }
70              catch (Exception ex)
71              {
72                  logger.error("Could not access OS environment: ", ex);
73                  environment = Collections.EMPTY_MAP;
74              }
75          }
76  
77          return environment;
78      }
79  
80      private static Map getenvJDK14() throws Exception
81      {
82          Map env = new HashMap();
83          Process process = null;
84  
85          try
86          {
87              boolean isUnix = true;
88              String command;
89  
90              if (SystemUtils.IS_OS_WINDOWS)
91              {
92                  command = "cmd /c set";
93                  isUnix = false;
94              }
95              else
96              {
97                  command = "env";
98              }
99  
100             process = Runtime.getRuntime().exec(command);
101             BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
102 
103             String line;
104             while ((line = br.readLine()) != null)
105             {
106                 for (int prefix = 0; prefix < UNIX_ENV_PREFIXES.length; prefix++)
107                 {
108                     if (line.startsWith(UNIX_ENV_PREFIXES[prefix]))
109                     {
110                         line = line.substring(UNIX_ENV_PREFIXES[prefix].length());
111                     }
112                 }
113 
114                 int index = -1;
115                 if ((index = line.indexOf('=')) > -1)
116                 {
117                     String key = line.substring(0, index).trim();
118                     String value = line.substring(index + 1).trim();
119                     // remove quotes, if any
120                     if (isUnix && value.length() > 1 && (value.startsWith("\"") || value.startsWith("'")))
121                     {
122                         value = value.substring(1, value.length() - 1);
123                     }
124                     env.put(key, value);
125                 }
126                 else
127                 {
128                     env.put(line, StringUtils.EMPTY);
129                 }
130             }
131         }
132         catch (Exception e)
133         {
134             throw e; // bubble up
135         }
136         finally
137         {
138             if (process != null)
139             {
140                 process.destroy();
141             }
142         }
143 
144         return env;
145     }
146 
147     public static String getenv(String name)
148     {
149         return (String) SystemUtils.getenv().get(name);
150     }
151 
152     public static boolean isSunJDK()
153     {
154         return SystemUtils.JAVA_VM_VENDOR.toUpperCase().indexOf("SUN") != -1;
155     }
156 
157     public static boolean isAppleJDK()
158     {
159         return SystemUtils.JAVA_VM_VENDOR.toUpperCase().indexOf("APPLE") != -1;
160     }
161 
162     public static boolean isIbmJDK()
163     {
164         return SystemUtils.JAVA_VM_VENDOR.toUpperCase().indexOf("IBM") != -1;
165     }
166 
167     // TODO MULE-1947 Command-line arguments should be handled exclusively by the bootloader
168 
169     private static CommandLine parseCommandLine(String args[], String opts[][]) throws DefaultMuleException
170     {
171         Options options = new Options();
172         for (int i = 0; i < opts.length; i++)
173         {
174             options.addOption(opts[i][0], opts[i][1].equals("true") ? true : false, opts[i][2]);
175         }
176 
177         BasicParser parser = new BasicParser();
178 
179         try
180         {
181             CommandLine line = parser.parse(options, args, true);
182             if (line == null)
183             {
184                 throw new DefaultMuleException("Unknown error parsing the Mule command line");
185             }
186 
187             return line;
188         }
189         catch (ParseException p)
190         {
191             throw new DefaultMuleException("Unable to parse the Mule command line because of: " + p.toString(), p);
192         }
193     }
194 
195     /**
196      * Returns the value corresponding to the given option from the command line, for
197      * example if the options are "-config mule-config.xml"
198      * getCommandLineOption("config") would return "mule-config.xml"
199      */
200     // TODO MULE-1947 Command-line arguments should be handled exclusively by the bootloader
201     public static String getCommandLineOption(String option, String args[], String opts[][])
202             throws DefaultMuleException
203     {
204         CommandLine line = parseCommandLine(args, opts);
205         return line.getOptionValue(option);
206     }
207 
208     /**
209      * Checks whether a command line option is set. This is useful for command line
210      * options that don't have an argument, like "-cluster", which means that this
211      * Mule instance is part of a cluster.
212      */
213     // TODO MULE-1947 Command-line arguments should be handled exclusively by the bootloader
214     public static boolean hasCommandLineOption(String option, String args[], String opts[][])
215             throws DefaultMuleException
216     {
217         CommandLine line = parseCommandLine(args, opts);
218         return line.hasOption(option);
219     }
220 
221     /**
222      * Returns a Map of all options in the command line. The Map is keyed off the
223      * option name. The value will be whatever is present on the command line.
224      * Options that don't have an argument will have the String "true".
225      */
226     // TODO MULE-1947 Command-line arguments should be handled exclusively by the bootloader
227     public static Map<String, Object> getCommandLineOptions(String args[], String opts[][]) throws DefaultMuleException
228     {
229         CommandLine line = parseCommandLine(args, opts);
230         Map<String, Object> ret = new HashMap<String, Object>();
231         Option[] options = line.getOptions();
232 
233         for (int i = 0; i < options.length; i++)
234         {
235             Option option = options[i];
236             ret.put(option.getOpt(), option.getValue("true"));
237         }
238 
239         return ret;
240     }
241 
242     /**
243      * Returns a Map of all valid property definitions in <code>-Dkey=value</code>
244      * format. <code>-Dkey</code> is interpreted as <code>-Dkey=true</code>,
245      * everything else is ignored. Whitespace in values is properly handled but needs
246      * to be quoted properly: <code>-Dkey="some value"</code>.
247      *
248      * @param input String with property definitionn
249      * @return a {@link Map} of property String keys with their defined values
250      *         (Strings). If no valid key-value pairs can be parsed, the map is
251      *         empty.
252      */
253     public static Map<String, String> parsePropertyDefinitions(String input)
254     {
255         if (StringUtils.isEmpty(input))
256         {
257             return Collections.emptyMap();
258         }
259 
260         // the result map of property key/value pairs
261         final Map<String, String> result = new HashMap<String, String>();
262 
263         // where to begin looking for key/value tokens
264         int tokenStart = 0;
265 
266         // this is the main loop that scans for all tokens
267         findtoken:
268         while (tokenStart < input.length())
269         {
270             // find first definition or bail
271             tokenStart = StringUtils.indexOf(input, "-D", tokenStart);
272             if (tokenStart == StringUtils.INDEX_NOT_FOUND)
273             {
274                 break findtoken;
275             }
276             else
277             {
278                 // skip leading -D
279                 tokenStart += 2;
280             }
281 
282             // find key
283             int keyStart = tokenStart;
284             int keyEnd = keyStart;
285 
286             if (keyStart == input.length())
287             {
288                 // short input: '-D' only
289                 break;
290             }
291 
292             // let's check out what we have next
293             char cursor = input.charAt(keyStart);
294 
295             // '-D xxx'
296             if (cursor == ' ')
297             {
298                 continue findtoken;
299             }
300 
301             // '-D='
302             if (cursor == '=')
303             {
304                 // skip over garbage to next potential definition
305                 tokenStart = StringUtils.indexOf(input, ' ', tokenStart);
306                 if (tokenStart != StringUtils.INDEX_NOT_FOUND)
307                 {
308                     // '-D= ..' - continue with next token
309                     continue findtoken;
310                 }
311                 else
312                 {
313                     // '-D=' - get out of here
314                     break findtoken;
315                 }
316             }
317 
318             // apparently there's a key, so find the end
319             findkey:
320             while (keyEnd < input.length())
321             {
322                 cursor = input.charAt(keyEnd);
323 
324                 // '-Dkey ..'
325                 if (cursor == ' ')
326                 {
327                     tokenStart = keyEnd;
328                     break findkey;
329                 }
330 
331                 // '-Dkey=..'
332                 if (cursor == '=')
333                 {
334                     break findkey;
335                 }
336 
337                 // keep looking
338                 keyEnd++;
339             }
340 
341             // yay, finally a key
342             String key = StringUtils.substring(input, keyStart, keyEnd);
343 
344             // assume that there is no value following
345             int valueStart = keyEnd;
346             int valueEnd = keyEnd;
347 
348             // default value
349             String value = "true";
350 
351             // now find the value, but only if the current cursor is not a space
352             if (keyEnd < input.length() && cursor != ' ')
353             {
354                 // bump value start/end
355                 valueStart = keyEnd + 1;
356                 valueEnd = valueStart;
357 
358                 // '-Dkey="..'
359                 cursor = input.charAt(valueStart);
360                 if (cursor == '"')
361                 {
362                     // opening "
363                     valueEnd = StringUtils.indexOf(input, '"', ++valueStart);
364                 }
365                 else
366                 {
367                     // unquoted value
368                     valueEnd = StringUtils.indexOf(input, ' ', valueStart);
369                 }
370 
371                 // no '"' or ' ' delimiter found - use the rest of the string
372                 if (valueEnd == StringUtils.INDEX_NOT_FOUND)
373                 {
374                     valueEnd = input.length();
375                 }
376 
377                 // create value
378                 value = StringUtils.substring(input, valueStart, valueEnd);
379             }
380 
381             // finally create key and value && loop again for next token
382             result.put(key, value);
383 
384             // start next search at end of value
385             tokenStart = valueEnd;
386         }
387 
388         return result;
389     }
390 
391     /**
392      * Ensure a generated file name is legal.
393      */
394     public static String legalizeFileName(String name)
395     {
396         if (!SystemUtils.IS_OS_WINDOWS)
397         {
398             return name;
399         }
400 
401         // Assume slashes are deliberate.  Change other illegal characters
402         return name.replaceAll("[:\\\\]", "_");
403     }
404 
405 }