I have two programms "a" and "b" bot compiled to fatJar files. "b" is added as resource to "a". I now want "a" to execute "b" using a process builder. As far as I understand it I cannot directly give the process builder the "b" jar for it doesn't exist in the regular windows file system.
The suggested solution to this is to access "b" as resource and write its content to a temp file and then hand the temp file to the process builder.
My question is: how do i copy the fatJar "b" into a temp file in a way it stays executionable?
My current approach looks like this:
try {
Path tempFile = Files.createTempFile("b", ".jar");
InputStream stream = Main.class.getClassLoader().getResourceAsStream("b.jar");
try (InputStreamReader streamReader =
new InputStreamReader(stream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(streamReader)) {
String line;
while ((line = reader.readLine()) != null) {
Files.write(tempFile, reader.readLine().getBytes(StandardCharsets.UTF_8));
}
} catch (IOException e) {
e.printStackTrace();
}
ProcessBuilder processBuilder = new ProcessBuilder("java", "-jar", tempFile.getFileName().toString());
processBuilder.directory(new File(tempFile.getParent().toString()));
Process process = processBuilder.start();
processBuilder.redirectErrorStream(true);
System.out.println(process.isAlive());
The process.isAlive() call confirms the process is running however the process doesn't function as it should (it should build up a two way communication via the input and output streams but i won't get any answer from the running process).
Does anyone know if there is an better approach to the whole situation or if my way of copying the .jar to the temp file is wrong?
Ok so meanwhile i figured it out. Turns out the Buffered reader caused the problem. The below code works fine now.
Path tempFile = Files.createTempFile("b", ".jar");
InputStream stream = Main.class.getClassLoader().getResourceAsStream("b.jar");
byte[] line = stream.readAllBytes();
Files.write(tempFile, line);
ProcessBuilder processBuilder = new ProcessBuilder("java", "-jar", tempFile.getFileName().toString());
processBuilder.directory(new File(tempFile.getParent().toString()));
Process process = processBuilder.start();
Related
Im trying to code an app that starts a server using php binary. However when i read the output from the /data/data/com.mycompany.myapp/php using a BufferedReader, my app is freezing while appending output lines in the while statement. How do i fix this?
as.copy("php", new File("/data/data/com.mycompany.myapp"));
Runtime.getRuntime().exec("/system/bin/chmod 744 /data/data/com.mycompany.myapp/php");
new File("/data/data/com.mycompany.myapp/php").setExecutable(true);
new File("/sdcard/PocketMine-MP/PocketMine-MP.phar").setExecutable(true);
Runtime.getRuntime().exec("/system/bin/chmod -R 777 /sdcard/PocketMine-MP");
String[] startserver = {"/data/data/com.mycompany.myapp/php","/sdcard/PocketMine-MP/PocketMine-MP.phar","eng"};
final ProcessBuilder processbuilder = new ProcessBuilder(startserver);
processbuilder.directory(new File("/data/data/com.mycompany.myapp"));
processbuilder.environment().put("TMPDIR","/sdcard/PocketMine-MP/tmp");
processbuilder.redirectErrorStream();
java.lang.Process process = processbuilder.start();
InputStream is = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
StringBuilder builder = new StringBuilder();
while(br.readLine() != null){
builder.append(br.readLine()+"\n");
}
t.append(builder);
}catch(Exception e){
Toast.makeText(getApplicationContext(),e.toString(),Toast.LENGTH_LONG).show();
}
}
}
The cause of a process apparently pausing some time after ProcessBuilder.start() is often related to your application not consuming the stdout and stderr streams as they are generated. You can test this quickly by directing them to a file and read from the files after proc.waitFor ends. Add:
File outf = new File(TEMPDIR, "run.out");
File errf = new File(TEMPDIR, "run.err");
pb.redirectOutput(outf);
pb.redirectError(errf);
If that works, keep using the file redirect or set up a Runnable/Thread to consume both of getInputStream / getErrorStream.
I am running some .jar programs from a Java code. To do that, I use ProcessBuilder, as follows:
ProcessBuilder pb = new ProcessBuilder("java", "-jar", jarFile, configFile);
Process p = pb.start();
finished = p.waitFor(600, TimeUnit.SECONDS);
// print the error output
if(finished){
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ( (line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
result = builder.toString();
reader.close();
status = p.exitValue();
}
else{
p.destroyForcibly();
result = "Error: maximum time (600 seconds) exceeded.";
}
The above code is within a foor bucle that selects different jar files (using the jarFile variable) at each iteration. Each one of the jar files writes some output files (note that these output files are different from the standard output / standard error of the program, they are other additional output files).
The problem is that, sometimes, some of the jar programs do not create its corresponding files. If I re-run the code several times, the processes that write their output files are different in each execution (which is very rare).
Could someone give me an indication on how to solve this problem? Thanks in advance.
This question already has answers here:
How to execute script from JAR file?
(3 answers)
Closed 7 years ago.
I have class that invokes perl script:
Runtime.getRuntime().exec(perlscript.pl)
The class and the script are placed on the same jar archive. This jar was built by maven. And perl script was placed in root of the jar, but the class not in root path.
When I launch the perl script I get error: "The system cannot find the file specified"
Where should I place the script to properly invoke it?
This works both, in Eclipse and as a Maven-built jar. Following what is said in this SO answer, what I've done is (i) find the original script within the jar, (ii) copy its content into a newly created file within a temporary folder and finally (iii) -- execute that script:
// find the original script within the JAR,
// mine sits in /src/main/resources/Perl/Hello.pl
InputStream in = PerlCaller.class.getClass().getResourceAsStream("/Perl/Hello.pl");
// if the file in the jar's root
// InputStream in = PerlCaller.class.getClass().getResourceAsStream("/Hello.pl");
if (null == in) {
System.err.println("Resource ws not found, exiting...");
System.exit(10);
}
// copy its content into a temporary file, I use strings since it's a script
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
File scriptFile = File.createTempFile("perlscript", ".pl");
BufferedWriter bw = new BufferedWriter(new FileWriter(scriptFile));
String line;
while ((line = reader.readLine()) != null) {
bw.write(line + "\n");
}
bw.close();
// execute the newly created file
String[] command = { "perl", scriptFile.getAbsolutePath() };
final ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
final Process p = pb.start();
BufferedReader outputReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringBuilder builder = new StringBuilder();
String outputLine = null;
while ((outputLine = outputReader.readLine()) != null) {
builder.append(outputLine);
builder.append(System.getProperty("line.separator"));
}
String scriptOutput = builder.toString();
System.out.println(scriptOutput);
Hope this helps!
You can access you script as a stream like:
Thread.currentThread().getContextClassLoader().getResourceAsStream("script.pl");
if your script is not in the root of classpath, use slashes to point to it like:
"path/to/script/script.pl"
I want to run a exe program from my Java application.I try this code for it.
I run the batch file and batch file runs the exe.
try {
String command = "C:\\tryfile\\Runprogram.bat";
// ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", command);
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
Process p = pb.start();
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
int excode = p.waitFor();
System.out.println(excode + " asfasf");
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}
The exe runs well and does what I want.(It insert from csv file to database with bcp).There is no problem about it.
But waitfor method returns 2147483647.
What is it?I have no idea about it.I know that if the exe run and finish without any error it returns 0 normally.But my exe returns 2147483647.
Any idea?
My bat file is here:
C:\tryfile\myprogram.exe
You are getting the exit code of the BAT, not the return code of the EXE. But you have not specified an exit code in your BAT so you get trash.
I don't have a windows box on hand but something like this should work
C:\tryfile\myprogram.exe
EXIT /B %ERRORLEVEL%
Check Batch files - Errorlevels
Okay i'm trying to make ChucK available in exported Processing sketches, i.e. if i export an app from Processing, the ChucK VM binary will be executed from inside the app. So as a user of said app you don't need to worry about ChucK being in your path at all.
Right now i'm generating and executing a bash script file, but this way i don't get any console output from ChucK back into Processing:
#!/bin/bash
cd "[to where the Chuck executable is located]"
./chuck --kill
killall chuck # just to make sure
./chuck chuckScript1.ck cuckScriptn.ck
then
Process p = Runtime.getRuntime().exec("chmod 777 "+scriptPath);
p = Runtime.getRuntime().exec(scriptPath);
This works but i want to run ChucK directly from Processing instead, but can't get it to execute:
String chuckPath = "[folder in which the chuck executable is located]"
ProcessBuilder builder = new ProcessBuilder
(chuckPath+"/chuck", "test.ck");
final Process process = builder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while((line = br.readLine()) != null) println(line);
println("done chuckin'! exitValue: " + process.exitValue());
Sorry if this is newbie style :D
ProcessBuilder builder = new ProcessBuilder
(chuckPath+"/chuck", chuckPath+"/test.ck");
the args all need an absolute path.