View Javadoc

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