View Javadoc

1   // 
2   // Copyright (c) 2003-2005, Caltha - Gajda, Krzewski, Mach, Potempski Sp.J. 
3   // All rights reserved. 
4   //   
5   // Redistribution and use in source and binary forms, with or without modification,  
6   // are permitted provided that the following conditions are met: 
7   //   
8   // * Redistributions of source code must retain the above copyright notice,  
9   // this list of conditions and the following disclaimer. 
10  // * Redistributions in binary form must reproduce the above copyright notice,  
11  // this list of conditions and the following disclaimer in the documentation  
12  // and/or other materials provided with the distribution. 
13  // * Neither the name of the Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.  
14  // nor the names of its contributors may be used to endorse or promote products  
15  // derived from this software without specific prior written permission. 
16  // 
17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
18  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
19  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
20  // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  
21  // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  
22  // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
23  // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
24  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
25  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
26  // POSSIBILITY OF SUCH DAMAGE. 
27  //
28  
29  package org.objectledge.external;
30  
31  import java.io.BufferedInputStream;
32  import java.io.BufferedOutputStream;
33  import java.io.File;
34  import java.io.FileInputStream;
35  import java.io.FileOutputStream;
36  import java.io.IOException;
37  import java.io.OutputStream;
38  
39  import org.jcontainer.dna.Configuration;
40  import org.jcontainer.dna.Logger;
41  import org.objectledge.utils.StringUtils;
42  
43  /***
44   * @author <a href="rafal@caltha.pl">RafaƂ Krzewski</a>
45   * @version $Id: ProcessExecutor.java,v 1.2 2006/03/28 18:02:38 zwierzem Exp $
46   */
47  public class ProcessExecutor
48  {
49      /***
50       * Default shell invocation format.
51       */
52      public static final String DEFAULT_SHELL = "sh -c";
53  
54      /***
55       * Shell invocation format.
56       */
57      private final String[] shellTokens;
58  
59      /*** The logger. */
60      private final Logger log;
61  
62      /***
63       * Creates a new ProcessExecutor instance.
64       * 
65       * @param logger the logger to use.
66       * @param shell the shell invocation format.
67       */
68      public ProcessExecutor(Logger logger, String shell)
69      {
70          this.log = logger;
71          this.shellTokens = shell.split(" ");
72      }
73  
74      /***
75       * Creates a new ProcessExecutor instance.
76       * 
77       * @param logger the logger to use.
78       * @param configuration component configuration.
79       */
80      public ProcessExecutor(Logger logger, Configuration configuration)
81      {
82          this(logger, configuration.getChild("shell").getValue(DEFAULT_SHELL));
83      }
84  
85      /***
86       * Execute an external process.
87       * <p>
88       * No data is sent to the process input stream, output and error streams are not captured.
89       * </p>
90       * 
91       * @param args the script name and arguments.
92       * @return execution result.
93       * @throws IOException If the execution fails.
94       */
95      public ExecutionResult exec(String... args)
96          throws IOException
97      {
98          String cmd = concat(args);
99          log.debug("executing " + cmd);
100         try
101         {
102             Process process = Runtime.getRuntime().exec(args);
103             process.waitFor();
104             return new ExecutionResult(process.exitValue());
105         }
106         catch(InterruptedException e)
107         {
108             throw new IOException("execution interrupted");
109         }
110     }
111 
112     /***
113      * Executes an external process.
114      * 
115      * @param input data to be passed to the process inpupt stream.
116      * @param captureOutput should process output stream be captured.
117      * @param captureError should process error stream be captured.
118      * @param args process executable name and arguments.
119      * @return execution result.
120      * @throws IOException If the execution fails.
121      */
122     public ExecutionResult exec(byte[] input, boolean captureOutput, boolean captureError,
123         String... args)
124         throws IOException
125     {
126         String cmd = concat(args);
127         File in = null;
128         File out = null;
129         File err = null;
130         try
131         {
132             boolean redirect = false;
133             if(input != null)
134             {
135                 in = File.createTempFile("ledge-in-", ".tmp");
136                 write(in, input);
137                 args = StringUtils.push(args, "<" + in.getPath());
138                 redirect = true;
139             }
140             if(captureOutput)
141             {
142                 out = File.createTempFile("ledge-out-", ".tmp");
143                 args = StringUtils.push(args, ">" + out.getPath());
144                 redirect = true;
145             }
146             if(captureError)
147             {
148                 err = File.createTempFile("ledge-err-", ".tmp");
149                 args = StringUtils.push(args, "2>" + err.getPath());
150                 redirect = true;
151             }
152 
153             Process process;
154             if(redirect)
155             {
156                 args = StringUtils.push(shellTokens, concat(args));
157                 cmd = concat(args);
158             }
159             log.debug("executing " + cmd);
160             process = Runtime.getRuntime().exec(args);
161             process.waitFor();
162             return new ExecutionResult(process.exitValue(), read(out), read(err));
163         }
164         catch(InterruptedException e)
165         {
166             throw new IOException("execution interrupted");
167         }
168         finally
169         {
170             release(in);
171             release(out);
172             release(err);
173         }
174     }
175 
176     /***
177      * Executes an external process.
178      * 
179      * @param input data to be passed to the process inpupt stream.
180      * @param captureOutput should process output stream be captured.
181      * @param captureError should process error stream be captured.
182      * @param args process executable name and arguments.
183      * @return execution result.
184      * @throws IOException
185      * @throws IOException If the execution fails.
186      */
187     public ExecutionResult exec(String input, boolean captureOutput, boolean captureError,
188         String... args)
189         throws IOException
190     {
191         return exec(StringUtils.toUTF8(input), captureOutput, captureError, args);
192     }
193 
194     /***
195      * Executes an external process.
196      * 
197      * @param captureOutput should process output stream be captured.
198      * @param captureError should process error stream be captured.
199      * @param args process executable name and arguments.
200      * @return execution result.
201      * @throws IOException 
202      * @throws IOException If the execution fails.
203      */
204     public ExecutionResult exec(boolean captureOutput, boolean captureError, String... args)
205         throws IOException
206     {
207         return exec((byte[])null, captureOutput, captureError, args);
208     }
209 
210     private byte[] read(File file)
211         throws IOException
212     {
213         if(file == null)
214         {
215             return null;
216         }
217         BufferedInputStream is = new BufferedInputStream(new FileInputStream(file));
218         byte[] result = new byte[(int)file.length()];
219         is.read(result);
220         return result;
221     }
222 
223     private void write(File file, byte[] bytes)
224         throws IOException
225     {
226         OutputStream fos = new BufferedOutputStream(new FileOutputStream(file));
227         fos.write(bytes);
228         fos.close();
229     }
230 
231     private void release(File file)
232     {
233         if(file != null && file.exists() && !log.isDebugEnabled())
234         {
235             file.delete();
236         }
237     }
238 
239     private String concat(String[] args)
240     {
241         StringBuffer buff = new StringBuffer();
242         for(int i = 0; i < args.length; i++)
243         {
244             buff.append(args[i]);
245             if(i < args.length - 1)
246             {
247                 buff.append(' ');
248             }
249         }
250         return buff.toString();
251     }
252 }