root / trunk / build / distribution / IzPack / src / lib / com / izforge / izpack / util / FileExecutor.java @ 21757
History | View | Annotate | Download (10.7 KB)
1 |
/*
|
---|---|
2 |
* $Id: FileExecutor.java 5819 2006-06-14 07:29:09Z cesar $
|
3 |
* IzPack
|
4 |
* Copyright (C) 2002 Olexij Tkatchenko
|
5 |
*
|
6 |
* File : FileExecutor.java
|
7 |
* Description : File execution class.
|
8 |
* Author's email : ot@parcs.de
|
9 |
* Website : http://www.izforge.com
|
10 |
*
|
11 |
* This program is free software; you can redistribute it and/or
|
12 |
* modify it under the terms of the GNU General Public License
|
13 |
* as published by the Free Software Foundation; either version 2
|
14 |
* of the License, or any later version.
|
15 |
*
|
16 |
* This program is distributed in the hope that it will be useful,
|
17 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
19 |
* GNU General Public License for more details.
|
20 |
*
|
21 |
* You should have received a copy of the GNU General Public License
|
22 |
* along with this program; if not, write to the Free Software
|
23 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
24 |
*/
|
25 |
package com.izforge.izpack.util; |
26 |
|
27 |
import java.io.BufferedReader; |
28 |
import java.io.BufferedWriter; |
29 |
import java.io.File; |
30 |
import java.io.IOException; |
31 |
import java.io.InputStreamReader; |
32 |
import java.io.Reader; |
33 |
import java.io.StringWriter; |
34 |
import java.io.Writer; |
35 |
import java.util.ArrayList; |
36 |
import java.util.Collection; |
37 |
import java.util.Iterator; |
38 |
import java.util.List; |
39 |
|
40 |
import com.izforge.izpack.ExecutableFile; |
41 |
|
42 |
/**
|
43 |
* Executes a bunch of files. This class is intended to do a system dependent
|
44 |
* installation postprocessing. Executable file can be any file installed with
|
45 |
* current package. After execution the file can be optionally removed. Before
|
46 |
* execution on Unix systems execution flag will be set on processed file.
|
47 |
*
|
48 |
* @author Olexij Tkatchenko <ot@parcs.de>
|
49 |
*/
|
50 |
public class FileExecutor |
51 |
{ |
52 |
/**
|
53 |
* This is a grabber for stdout and stderr. It will be launched once at
|
54 |
* command execution end terminates if the apropriate stream runs out of
|
55 |
* data.
|
56 |
*
|
57 |
* @author Olexij Tkatchenko <ot@parcs.de>
|
58 |
*/
|
59 |
private static class MonitorInputStream implements Runnable |
60 |
{ |
61 |
|
62 |
private BufferedReader reader; |
63 |
private BufferedWriter writer; |
64 |
private boolean shouldStop = false; |
65 |
|
66 |
|
67 |
public MonitorInputStream(Reader in, Writer out) |
68 |
{ |
69 |
reader = new BufferedReader(in); |
70 |
writer = new BufferedWriter(out); |
71 |
} |
72 |
|
73 |
|
74 |
public void doStop() |
75 |
{ |
76 |
shouldStop = true;
|
77 |
} |
78 |
|
79 |
|
80 |
public void run() |
81 |
{ |
82 |
try
|
83 |
{ |
84 |
String line;
|
85 |
while ((line = reader.readLine()) != null) |
86 |
{ |
87 |
writer.write(line); |
88 |
writer.newLine(); |
89 |
writer.flush(); |
90 |
if (shouldStop)
|
91 |
return;
|
92 |
} |
93 |
} |
94 |
catch (IOException ioe) |
95 |
{ |
96 |
ioe.printStackTrace(System.out);
|
97 |
} |
98 |
} |
99 |
} |
100 |
|
101 |
|
102 |
private boolean stopThread(Thread t, MonitorInputStream m) |
103 |
{ |
104 |
m.doStop(); |
105 |
long softTimeout = 1000; |
106 |
try
|
107 |
{ |
108 |
t.join(softTimeout); |
109 |
} |
110 |
catch (InterruptedException e) |
111 |
{} |
112 |
|
113 |
if (!t.isAlive())
|
114 |
return true; |
115 |
|
116 |
t.interrupt(); |
117 |
long hardTimeout = 1000; |
118 |
try
|
119 |
{ |
120 |
t.join(hardTimeout); |
121 |
} |
122 |
catch (InterruptedException e) |
123 |
{} |
124 |
return !t.isAlive();
|
125 |
} |
126 |
|
127 |
|
128 |
/**
|
129 |
* Constructs a new executor. The executable files specified must have
|
130 |
* pretranslated paths (variables expanded and file separator characters
|
131 |
* converted if necessary).
|
132 |
*
|
133 |
* @param files the executable files to process
|
134 |
*/
|
135 |
public FileExecutor(Collection files) |
136 |
{ |
137 |
this.files = files;
|
138 |
} |
139 |
|
140 |
|
141 |
/**
|
142 |
* Constructs a new executor.
|
143 |
*/
|
144 |
public FileExecutor ()
|
145 |
{ |
146 |
this.files = null; |
147 |
} |
148 |
|
149 |
/**
|
150 |
* Executed a system command and waits for completion.
|
151 |
*
|
152 |
* @param params system command as string array
|
153 |
* @param output contains output of the command
|
154 |
* index 0 = standard output
|
155 |
* index 1 = standard error
|
156 |
* @return exit status of process
|
157 |
*/
|
158 |
public int executeCommand(String[] params, String[] output) |
159 |
{ |
160 |
StringBuffer retval = new StringBuffer(); |
161 |
retval.append("executeCommand\n");
|
162 |
if (params != null) |
163 |
{ |
164 |
for (int i = 0; i < params.length; i++) |
165 |
{ |
166 |
retval.append("\tparams: "+params[i]);
|
167 |
retval.append("\n");
|
168 |
} |
169 |
} |
170 |
Process process = null; |
171 |
MonitorInputStream outMonitor = null;
|
172 |
MonitorInputStream errMonitor = null;
|
173 |
Thread t1 = null; |
174 |
Thread t2 = null; |
175 |
int exitStatus = -1; |
176 |
|
177 |
Debug.trace(retval); |
178 |
|
179 |
try
|
180 |
{ |
181 |
// execute command
|
182 |
process = Runtime.getRuntime().exec(params);
|
183 |
|
184 |
boolean console = false;//TODO: impl from xml <execute in_console=true ...>, but works already if this flag is true |
185 |
if (console)
|
186 |
{ |
187 |
Console c = new Console(process);
|
188 |
// save command output
|
189 |
output[0] = c.getOutputData();
|
190 |
output[1] = c.getErrorData();
|
191 |
exitStatus = process.exitValue(); |
192 |
} |
193 |
else
|
194 |
{ |
195 |
StringWriter outWriter = new StringWriter(); |
196 |
StringWriter errWriter = new StringWriter(); |
197 |
|
198 |
InputStreamReader or =
|
199 |
new InputStreamReader(process.getInputStream()); |
200 |
InputStreamReader er =
|
201 |
new InputStreamReader(process.getErrorStream()); |
202 |
outMonitor = new MonitorInputStream(or, outWriter);
|
203 |
errMonitor = new MonitorInputStream(er, errWriter);
|
204 |
t1 = new Thread(outMonitor); |
205 |
t2 = new Thread(errMonitor); |
206 |
t1.setDaemon(true);
|
207 |
t2.setDaemon(true);
|
208 |
t1.start(); |
209 |
t2.start(); |
210 |
|
211 |
// wait for command to complete
|
212 |
exitStatus = process.waitFor(); |
213 |
t1.join(); |
214 |
t2.join(); |
215 |
|
216 |
// save command output
|
217 |
output[0] = outWriter.toString();
|
218 |
Debug.trace ("stdout:");
|
219 |
Debug.trace (output[0]);
|
220 |
output[1] = errWriter.toString();
|
221 |
Debug.trace ("stderr:");
|
222 |
Debug.trace (output[1]);
|
223 |
} |
224 |
Debug.trace ("exit status: " + Integer.toString (exitStatus)); |
225 |
} |
226 |
catch (InterruptedException e) |
227 |
{ |
228 |
if (Debug.tracing()) e.printStackTrace(System.err); |
229 |
stopThread(t1, outMonitor); |
230 |
stopThread(t2, errMonitor); |
231 |
output[0] = ""; |
232 |
output[1] = e.getMessage() + "\n"; |
233 |
process.destroy(); |
234 |
} |
235 |
catch (IOException e) |
236 |
{ |
237 |
if (Debug.tracing()) e.printStackTrace(System.err); |
238 |
output[0] = ""; |
239 |
output[1] = e.getMessage() + "\n"; |
240 |
} |
241 |
return exitStatus;
|
242 |
} |
243 |
|
244 |
/**
|
245 |
* Executes files specified at construction time.
|
246 |
*
|
247 |
* @param currentStage the stage of the installation
|
248 |
* @param handler The AbstractUIHandler to notify on errors.
|
249 |
*
|
250 |
* @return 0 on success, else the exit status of the last failed command
|
251 |
*/
|
252 |
public int executeFiles(int currentStage, AbstractUIHandler handler) |
253 |
{ |
254 |
int exitStatus = 0; |
255 |
String[] output = new String[2]; |
256 |
//String permissions = (System.getProperty("user.name").equals("root")) ? "a+x" : "u+x";
|
257 |
String permissions = "a+x"; |
258 |
|
259 |
// loop through all executables
|
260 |
Iterator efileIterator = files.iterator();
|
261 |
while (exitStatus == 0 && efileIterator.hasNext()) |
262 |
{ |
263 |
ExecutableFile efile = (ExecutableFile) efileIterator.next(); |
264 |
boolean deleteAfterwards = ! efile.keepFile;
|
265 |
File file = new File(efile.path); |
266 |
Debug.trace("handeling executable file "+efile);
|
267 |
|
268 |
// skip file if not for current OS (it might not have been installed at all)
|
269 |
if (! OsConstraint.oneMatchesCurrentSystem (efile.osList))
|
270 |
continue;
|
271 |
|
272 |
if(currentStage!=ExecutableFile.UNINSTALL && OsVersion.IS_UNIX)
|
273 |
{ |
274 |
// fix executable permission for unix systems
|
275 |
Debug.trace("making file executable (setting executable flag)");
|
276 |
String[] params = {"/bin/chmod", permissions, file.toString()}; |
277 |
exitStatus = executeCommand(params, output); |
278 |
if (exitStatus != 0) |
279 |
{ |
280 |
handler.emitError("file execution error", "Error executing \n"+ |
281 |
params[0]+" "+params[1]+" "+params[2]); |
282 |
continue;
|
283 |
} |
284 |
} |
285 |
|
286 |
// execute command in POSTINSTALL stage
|
287 |
if ((exitStatus == 0) && |
288 |
((currentStage == ExecutableFile.POSTINSTALL && efile.executionStage == ExecutableFile.POSTINSTALL) |
289 |
|| (currentStage==ExecutableFile.UNINSTALL && efile.executionStage == ExecutableFile.UNINSTALL))) |
290 |
{ |
291 |
List paramList = new ArrayList(); |
292 |
if (ExecutableFile.BIN == efile.type)
|
293 |
paramList.add(file.toString()); |
294 |
|
295 |
else if (ExecutableFile.JAR == efile.type && null == efile.mainClass) |
296 |
{ |
297 |
paramList.add(System.getProperty("java.home") + "/bin/java"); |
298 |
paramList.add("-jar");
|
299 |
paramList.add(file.toString()); |
300 |
} |
301 |
else if (ExecutableFile.JAR == efile.type && null != efile.mainClass) |
302 |
{ |
303 |
paramList.add(System.getProperty("java.home") + "/bin/java"); |
304 |
paramList.add("-cp");
|
305 |
paramList.add(file.toString()); |
306 |
paramList.add(efile.mainClass); |
307 |
} |
308 |
|
309 |
if (null != efile.argList && !efile.argList.isEmpty()) |
310 |
paramList.addAll(efile.argList); |
311 |
|
312 |
String[] params = new String[paramList.size()]; |
313 |
for (int i = 0; i < paramList.size(); i++) |
314 |
params[i] = (String) paramList.get(i);
|
315 |
|
316 |
exitStatus = executeCommand(params, output); |
317 |
|
318 |
// bring a dialog depending on return code and failure handling
|
319 |
if (exitStatus != 0) |
320 |
{ |
321 |
deleteAfterwards = false;
|
322 |
String message = output[0] + "\n" + output[1]; |
323 |
if (message.length() == 1) |
324 |
message = "Failed to execute " + file.toString() + "."; |
325 |
|
326 |
if (efile.onFailure == ExecutableFile.ABORT)
|
327 |
{ |
328 |
// CHECKME: let the user decide or abort anyway?
|
329 |
handler.emitError("file execution error", message);
|
330 |
} |
331 |
else if (efile.onFailure == ExecutableFile.WARN) |
332 |
{ |
333 |
// CHECKME: let the user decide or abort anyway?
|
334 |
handler.emitWarning ("file execution error", message);
|
335 |
exitStatus = 0;
|
336 |
} |
337 |
else
|
338 |
{ |
339 |
if (handler.askQuestion (null, "Continue?", AbstractUIHandler.CHOICES_YES_NO) |
340 |
== AbstractUIHandler.ANSWER_YES) |
341 |
exitStatus = 0;
|
342 |
} |
343 |
|
344 |
} |
345 |
|
346 |
} |
347 |
|
348 |
|
349 |
// POSTINSTALL executables will be deleted
|
350 |
if (efile.executionStage == ExecutableFile.POSTINSTALL && deleteAfterwards)
|
351 |
{ |
352 |
if (file.canWrite()) file.delete();
|
353 |
} |
354 |
|
355 |
} |
356 |
return exitStatus;
|
357 |
} |
358 |
|
359 |
/** The files to execute. */
|
360 |
private Collection files; |
361 |
} |
362 |
|