Running python script from jar file - java

I have been working on java app that uses python script to run some 3d visualization, it worked when I was running it from intellij but once I created jar file it just doesn't run. OS: MAC OS
How I run script:
Process p1 = Runtime.getRuntime().exec("python3 vizualize3D.py");

The problem had multiple layers and solutions:
1. I didn't put .py file in jar build config
2. After putting it I always got an exception that it is null because of a typo in code
3. After trying many ways to run it this one worked Cannot run python script from java jar
. The important thing is to check if you added py file to the build config and to run it in a proper way since python cannot runt files from the zip and compressed states.

Assuming the script is in the jar file, you can get an input stream from the resource, and use it as the input to a Process created from the python interpreter:
// Note: the path to the script here is relative to the current class
// and follows strict resource name rules, since this is in a jar file
InputStream script = getClass().getResourceAsStream("visualize3D.py");
// The following creates a process to run python3.
// This assumes python3 is on the system path. Provide the full
// path to the python3 interpreter (e.g. /usr/bin/python3) if it's
// not on the path.
// The - option to python3 instructs it to execute a script provided
// as standard input.
Process process = new ProcessBuilder("python3", "-")
.start() ;
OutputStream out = process.getOutputStream();
byte[] buffer = new byte[1024];
int read = 0;
while((read = script.read(buffer)) != -1) {
pos.write(buffer, 0, read);
}
script.close();
For details on getting the correct path for the script, see How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?

Related

Java InputStream with a shell script as input to Runtime.getRunTime().exec()

I am running a java program using a Jar file. Inside this packaged jar file I have my shell script. I understand that the best way to access the file would be through getResourcesAsStream because I can't access it via regular directory structures. So this is what I'm using:
InputStream input = this.getClass().getResourceAsStream("/script/sample_script.sh");
However, The only way I know how to execute this is if I go through the script line by line using a loop and bufferReader. I Statements like "If" or "While" loops get me an error. Is there a way to input the stream to achieve the desired results.
Here is my current code:
InputStream input = this.getClass().getResourceAsStream("/script/sample_script.sh");
BufferedReader brCmd = new BufferedReader(new InputStreamReader(input));
String cmd;
while ((cmd = brCmd.readLine()) != null){
proc = Runtime.getRuntime().exec(cmd);
proc.waitFor();
}
I've tried concatenating the whole file line by line to a string and using that but it doesn't seem to work. How can I get to make my script file run using inputStream? Any help would be appreciated
You could read the script file through InputStream and write it to a temp file under the system temp directory, and execute this file in following way:Runtime.getRuntime.exec("/bin/sh " + tempFilePath);
About reason to rewrite the script file to another temp file, you said you are executing your program by run the jar file directly, thus the script file is packed into the jar file and java won't unpack the jar file to the file system. To let the script file be accessible to cmd.exe, we need to rewrite the script file manually.
By the way, you could get the system temp directory path from system properties, or using apache common.io: FileUtils.getTempDirectory().

Controlling output file of a java jar using command line

I am using a .jar file, but unfortunatley as a black box, i.e. I do not know what exactly is in there nor how it all works.
I am sending commands to the Mac terminal from a Python script. I enter the following command:
java -jar jarfile.jar req_data /abs_path/to/required/data input path/to_my_/input/file.txt
This does what I need: analyses input using the 'black box' and creates and new file with analysis output. This new file is created in the folder where jarfile.jar is located.
I want to have this file put somewhere else upon creation.
I have tried using the > operator, specifying a path, e.g.:
java -jar jarfile.jar req_data /abs_path/to/required/data input path/to_my_/input/file.txt > /output/path/
this created a file in my desired location, but it was simply the message from Terminal, saying "The operation was carried out successfully" - the analysis results file was created in the same folder as before.
I tried %*> too, but it threw an error.
As a poor workaround I now have a function, which retrospectively finds and moves all the newly created files (analysis output) to my desired folder.
Is there a way to control the output files with the command line within the original command? Or is it something that is specified somewhere in my jar file? My problem is that editing it is not allowed.
I'm new to python. However, I may suggest to try few things, if they can work for you. Apology me, if does not work! I believe that you have already done the following step:
import subprocess
subprocess.call(['java', '-jar', 'Blender.jar'])
Like, if you have a properly configured jar path, then can run jar directly.
Secondly, look at the cwd parameter (is used for executable). Include a cwd param as x
def run_command(command, **x):
with subprocess.Popen(command,...., **x) as p:
for run_command specify the path of either the working directory (possibly it should be) or the full system path. I'm not sure, just try both.
for outputline in run_command(r'java -jar jarfilepath', cwd=r'workingdirpath', universal_newlines=True):
print(outputline, end='')
Alternatively, you can try to run command from the directory in which you wish to store output file. Try: run the popen as
subprocess.Popen(r'directory of running command', cwd=r'workingdir')
where workingdir could be your current directory path.
If it does not work, try without r'. If still does not work, try doubling slash in the path like (C:\\ abc\\def)

Run jar file from java application [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Run Java program into another Program
i try to run jar file from java application which was created in eclipse.
when i run jar file using below source code then fire Unable to access jarfile error
Process process = run.exec("java -jar TestJava.jar");
InputStream inError = process.getErrorStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inError));
System.out.println("Error=" + bufferedReader.readLine());
Sounds like TestJava.jar is in a different directory. If you're running this code within Eclipse, then the present working directory is going to be the same as your Eclipse project's folder (unless you've configured it differently, this is Eclipse's default run location). Either specify a path to TestJava.jar via an absolute path or a path relative to the present working directory.
One other thing you'll need to be mindful of - you need to consume both the error stream and the output stream of the Process you're creating. The default output/error stream buffer sizes of Process instances are not very big and, if full, will cause that Process to block indefinitely for more buffer space. I recommend consuming each stream in a separate Thread.
Set the working directory where this process should run. Set the working directory using the below statement.
Runtime.getRuntime().exec(command, null, new File("path_to_directory"));
First try the java -jar command on cmd window and see if you can run TestJava.jar. Then try running the same command from your code.
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("java -jar TestJava.jar");
System.exit(0);
You need to supply the full path to the Java command.
For example, under windows you'd need something like
C:/Program Files/java/jre/bin/java.exe
ProcessBuilder & Runtime.exec don't take the system path into account when trying to execute your command

How to run unix / shell commands with wildcards using Java?

I want to run some unix/shell commands in Java and process the output. I used getRuntime.exec(), but it is not giving correct output for some commands like ls directory_path/*.tar.gz . For that command my program is not giving any output but it is giving error saying No such file or directory. But the same command is giving correct output on command prompt.
Is there any other way to execute commands which include wildcards in Java?
Is there any other way to execute commands which include wildcards in Java?
Yes there is.
You have three potential problems in your code:
Assuming you want to see the output of the external command you need to take care of the output it produces, and print it yourself.
Follow the example I've provided over here:
How to make a java program to print both out.println() and err.println() statements?
The shell expansion of * doesn't work if you naively go through Runtime.exec.You have to go through /bin/bash explicitly.
If you try to list the content of directory_path/*.tar.gz you should know that (if you're not starting with a /) directory_path will be resolved relative to the current working directory. Try at first to give the absolute path to make sure it works, and then try to figure out why it can't find the relative path.
Here's a complete example that should work:
Process proc = new ProcessBuilder("/bin/bash", "-c",
"ls /.../directory_path/*.tar.gz").start();
Reader reader = new InputStreamReader(proc.getInputStream());
int ch;
while ((ch = reader.read()) != -1)
System.out.print((char) ch);
reader.close();
That is because you specified a relative path to the directory and your application is running in a working directory. The path you specified is relative to that working directory.
To find out what the absolute path is, you can check out the working directory.
System.out.println("Working directory: " + System.getProperty("user.dir"));
"ls directory_path/*.tar.gz" works relative to CURRENT directory.

directory structure to access .sh file from war

I have a .sh file i am creating a war file wheter in the classes are under web-inf/classes/test/test.class .i am accessing .sh file from test class using the following syntax
string cmd="./test.sh"
runtime api
i am not able to access this file if i place it under web-inf/classes .i want to know where can i place .s file in war to access the path from test.class as ./test.sh ?
According to your comment in the other question, you are using the following code to call your script:
Process p = Runtime.getRuntime().exec(cmd);
As explained in the javadoc, this is equivalent to the invocation of exec(command, null, null) which behaves in exactly the same way as the invocation exec(cmdarray, envp, dir). Now, if we look at the javadoc of exec(String[] cmdarray, String[] envp, File dir), we can read:
The working directory of the new subprocess is specified by dir. If dir is null, the subprocess inherits the current working directory of the current process.
In other words, in your case, your script test.sh is expected to be located in the working directory of your application server, i.e. the location in the file system from where the java command was invoked (which is certainly not WEB-INF/classes). This directory is set in the user.dir system property that you can read as follow:
String cwd = System.getProperty("user.dir")
Also note that you can't change the working directory. Actually, you should theoretically write your code so it does not depend on the current working directory for portability (even if this doesn't really matter in your case as using the Runtime API makes your code not really portable anyway).
To summarize, you have several options (none of them is really portable as I said but the last one is "less worse"):
Put the hello.sh script in the working directory of the app server.
Put it somewhere else and point on it relatively to the working directory (./path/to/hello.sh).
Put it somewhere else and point on it with an absolute path (/path/to/hello.sh).
Put it somewhere else and use the dir parameter when invoking exec().
Put it in the WAR and read it using getResourceAsStream(), write it in the tmp dir, make it executable and exec() it as suggested by Brian.
In my opinion, the last option is the (only) way to go and can be implemented like this (assuming the script is in the same package as your class i.e. WEB-INF/classes/test/hello.sh):
InputStream is = this.getClass().getResourceAsStream("hello.sh");
String[] cmd = null;
File tempFile = null;
tempFile = File.createTempFile("hello", "sh");
// extract the embedded hello.sh file from the war and save it to above file
OutputStream os = new FileOutputStream(tempFile);
byte[] buffer = new byte[1024];
int bytes;
while( (bytes = is.read(buffer)) != -1) {
os.write(buffer, 0, bytes);
}
os.close();
tempFile.setExecutable(true);
cmd = new String[] { tempFile.getAbsolutePath() };
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(cmd);
I would read the .sh via ClassLoader.getResourceAsStream().
You then have two choices:
Write it to a directory (perhaps /tmp ?), change the permissions and then execute it from there.
(a little more involved). Execute a /bin/bash via Runtime.exec() and then pipe the script in via stdin.
You won't be able to execute the script directly from the .war structure.

Categories