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