View Javadoc

1   package org.apache.maven.it.util.cli;
2   
3   /*
4    * The MIT License
5    *
6    * Copyright (c) 2004, The Codehaus
7    *
8    * Permission is hereby granted, free of charge, to any person obtaining a copy of
9    * this software and associated documentation files (the "Software"), to deal in
10   * the Software without restriction, including without limitation the rights to
11   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12   * of the Software, and to permit persons to whom the Software is furnished to do
13   * so, subject to the following conditions:
14   *
15   * The above copyright notice and this permission notice shall be included in all
16   * copies or substantial portions of the Software.
17   *
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24   * SOFTWARE.
25   */
26  
27  import java.io.BufferedReader;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.InputStreamReader;
31  import java.util.Collections;
32  import java.util.HashMap;
33  import java.util.Iterator;
34  import java.util.Locale;
35  import java.util.Map;
36  import java.util.Properties;
37  
38  /**
39   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l </a>
40   * @version $Id: CommandLineUtils.java 748485 2009-02-27 11:02:03Z bentmann $
41   */
42  public abstract class CommandLineUtils
43  {
44      private static Map processes = Collections.synchronizedMap( new HashMap() );
45  
46      private static Properties envVars;
47  
48      static
49      {
50          Runtime.getRuntime().addShutdownHook( new Thread( "CommandlineUtil shutdown" )
51          {
52              public void run()
53              {
54                  if ( ( processes != null ) && ( processes.size() > 0 ) )
55                  {
56                      System.err.println( "Destroying " + processes.size() + " processes" );
57                      for ( Iterator it = processes.values().iterator(); it.hasNext(); )
58                      {
59                          System.err.println( "Destroying process.." );
60                          ( (Process) it.next() ).destroy();
61  
62                      }
63                      System.err.println( "Destroyed " + processes.size() + " processes" );
64                  }
65              }
66          } );
67      }
68  
69      public static class StringStreamConsumer
70          implements StreamConsumer
71      {
72          private StringBuffer string = new StringBuffer();
73  
74          private String ls = System.getProperty( "line.separator" );
75  
76          public void consumeLine( String line )
77          {
78              string.append( line ).append( ls );
79          }
80  
81          public String getOutput()
82          {
83              return string.toString();
84          }
85      }
86  
87      public static int executeCommandLine( Commandline cl, StreamConsumer systemOut, StreamConsumer systemErr )
88          throws CommandLineException
89      {
90          return executeCommandLine( cl, null, systemOut, systemErr );
91      }
92  
93      public static int executeCommandLine( Commandline cl, InputStream systemIn, StreamConsumer systemOut,
94                                            StreamConsumer systemErr )
95          throws CommandLineException
96      {
97          if ( cl == null )
98          {
99              throw new IllegalArgumentException( "cl cannot be null." );
100         }
101 
102         Process p;
103 
104         p = cl.execute();
105 
106         processes.put( new Long( cl.getPid() ), p );
107 
108         StreamFeeder inputFeeder = null;
109 
110         if ( systemIn != null )
111         {
112             inputFeeder = new StreamFeeder( systemIn, p.getOutputStream() );
113         }
114 
115         StreamPumper outputPumper = new StreamPumper( p.getInputStream(), systemOut );
116 
117         StreamPumper errorPumper = new StreamPumper( p.getErrorStream(), systemErr );
118 
119         if ( inputFeeder != null )
120         {
121             inputFeeder.start();
122         }
123 
124         outputPumper.start();
125 
126         errorPumper.start();
127 
128         try
129         {
130             int returnValue = p.waitFor();
131 
132             if ( inputFeeder != null )
133             {
134                 synchronized ( inputFeeder )
135                 {
136                     if ( !inputFeeder.isDone() )
137                     {
138                         inputFeeder.wait();
139                     }
140                 }
141             }
142 
143             synchronized ( outputPumper )
144             {
145                 if ( !outputPumper.isDone() )
146                 {
147                     outputPumper.wait();
148                 }
149             }
150 
151             synchronized ( errorPumper )
152             {
153                 if ( !errorPumper.isDone() )
154                 {
155                     errorPumper.wait();
156                 }
157             }
158 
159             processes.remove( new Long( cl.getPid() ) );
160 
161             return returnValue;
162         }
163         catch ( InterruptedException ex )
164         {
165             killProcess( cl.getPid() );
166             throw new CommandLineException( "Error while executing external command, process killed.", ex );
167         }
168         finally
169         {
170             if ( inputFeeder != null )
171             {
172                 inputFeeder.close();
173             }
174 
175             outputPumper.close();
176 
177             errorPumper.close();
178         }
179     }
180 
181     public static Properties getSystemEnvVars()
182         throws IOException
183     {
184         if ( envVars == null )
185         {
186             envVars = getSystemEnvVars( true );
187         }
188 
189         Properties props = new Properties();
190         props.putAll( envVars );
191         return props;
192     }
193 
194     /**
195      * Return the shell environment variables. If <code>caseSensitive == true</code>, then envar
196      * keys will all be upper-case.
197      *
198      * @param caseSensitive Whether environment variable keys should be treated case-sensitively.
199      * @return Properties object of (possibly modified) envar keys mapped to their values.
200      * @throws IOException
201      */
202     public static Properties getSystemEnvVars( boolean caseSensitive )
203         throws IOException
204     {
205         Process p = null;
206 
207         Properties envVars = new Properties();
208 
209         Runtime r = Runtime.getRuntime();
210 
211         String os = System.getProperty( "os.name" ).toLowerCase( Locale.ENGLISH );
212 
213         //If this is windows set the shell to command.com or cmd.exe with correct arguments.
214         if ( os.indexOf( "windows" ) != -1 )
215         {
216             if ( os.indexOf( "95" ) != -1 || os.indexOf( "98" ) != -1 || os.indexOf( "Me" ) != -1 )
217             {
218                 p = r.exec( "command.com /c set" );
219             }
220             else
221             {
222                 p = r.exec( "cmd.exe /c set" );
223             }
224         }
225         else
226         {
227             p = r.exec( "env" );
228         }
229 
230         BufferedReader br = new BufferedReader( new InputStreamReader( p.getInputStream() ) );
231 
232         String line;
233 
234         String lastKey = null;
235         String lastVal = null;
236 
237         while ( ( line = br.readLine() ) != null )
238         {
239             int idx = line.indexOf( '=' );
240 
241             if ( idx > 1 )
242             {
243                 lastKey = line.substring( 0, idx );
244 
245                 if ( !caseSensitive )
246                 {
247                     lastKey = lastKey.toUpperCase();
248                 }
249 
250                 lastVal = line.substring( idx + 1 );
251 
252                 envVars.setProperty( lastKey, lastVal );
253             }
254             else if ( lastKey != null )
255             {
256                 lastVal += "\n" + line;
257 
258                 envVars.setProperty( lastKey, lastVal );
259             }
260         }
261 
262         return envVars;
263     }
264 
265     /**
266      * Kill a process launched by executeCommandLine methods
267      * Doesn't work correctly on windows, only the cmd process will be destroy but not the sub process (<a href="http://bugs.sun.com/bugdatabase/view_bug.do;:YfiG?bug_id=4770092">Bug ID 4770092</a>)
268      *
269      * @param pid The pid of command return by Commandline.getPid()
270      */
271     public static void killProcess( long pid )
272     {
273         Process p = (Process) processes.get( new Long( pid ) );
274 
275         if ( p != null )
276         {
277             p.destroy();
278             System.out.println( "killed." );
279             processes.remove( new Long( pid ) );
280         }
281         else
282         {
283             System.out.println( "don't exist." );
284         }
285     }
286 
287     public static boolean isAlive( long pid )
288     {
289         return ( processes.get( new Long( pid ) ) != null );
290     }
291 
292 }