Passing data from Java process to a python script - java

I call a external Python script as Java process and want to send data to this. I create a process and try to send a string. Later the python script should wait for a new input from Java, work with this data and wait again(while true loop).
Python Code (test.py):
input = input("")
print("Data: " + input)
Java Code:
Process p = Runtime.getRuntime().exec("py ./scripts/test.py");
BufferedWriter out = new BufferedWriter(new
OutputStreamWriter(p.getOutputStream()));
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
System.out.println("Output:");
String s = null;
out.write("testdata");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
The process and output of simple prints works, but not with input and BufferedWriter.
Is it possible to send data to this python input with a Java process?
I read from other solutions:
create a Python listener and send messages to this script
import the external script to Jython and pass data
Are this better solutions to handle my problem?

use Process class in java
what is process class ?
this class is used to start a .exe or any script using java
How it can help you
Create your python script to accept command line variables and send your data from java class to python script.
for Example:
System.out.println("Creating Process");
ProcessBuilder builder = new ProcessBuilder("my.py");
Process pro = builder.start();
// wait 10 seconds
System.out.println("Waiting");
Thread.sleep(10000);
// kill the process
pro.destroy();
System.out.println("Process destroyed");

Later the python script should wait for a new input from Java
If this has to happen while the python process is still a subprocess of the Java process, then you will have to use redirection of I/O using ProcessBuilder.redirect*( Redirect.INHERIT ) or ProcessBuilder.inheritIO(). Like this:
Process p = new ProcessBuilder().command( "python.exe", "./scripts/test.py" )
.inheritIO().start();
If the python process is going to be separate (which is not the case here, I think) then you will have to use some mechanism to communicate between them like client/server or shared file, etc.

Related

Infinite interprocess communication between java program and a python script

I want to achieve interprocess communication between my java app and the python script that it calls through its code.
The idea is that the python script runs in an infinite while loop, accepts input, processes the input and prints the result in the console.
Meanwhile, the java app sends the input, waits for the python script to process it, and reads it from the console (using InputStream from the python process, omitted for brevity) when the python script is done processing. How would one go about achieving this type of communication?
Java program
import java.io.*;
public class JavaProgram {
public static void main(String[] args) throws IOException{
Process p = Runtime.getRuntime().exec("python pythonScript.py");
OutputStream os = p.getOutputStream();
os.write("Hello".getBytes());
os.close();
os = p.getOutputStream();
os.write("World".getBytes());
os.close();
os = p.getOutputStream();
os.write("quit".getBytes());
os.close();
}
}
Python script
def transformString(string):
return "Java said: " + string
file = open("writingFile.txt", "w+")
while True:
user_input = input('\n> ')
message = transformString(user_input)
if message == "quit":
break
file.write(message + "\n")
print(message + "\n")
file.write("closing file...\n")
file.close()
The problem with the above code is that the java app can only send the input once (only "Hello" is sent) and then closes the output stream (tried without closing it). I know this because the python script never finished.
Here is the contents of the file writingFile.txt:
Java said: Hello
*Note: It's really important that the python script is started once, because the original script's init methods are time-consuming.
*Second note: The python's processing method also takes a bit of time, so how I don't know how to tell the java program when it's should start reading the output.

Calling Python from Java (Tomcat6) as sub-process

I am trying to call a python script from a java/tomcat6 webapp. I am currently using the following code:
Process p = Runtime.getRuntime().exec("python <file.py>");
InputStream in = p.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader b = new BufferedReader(isr);
logger.info("PYTHON OUTPUT");
String line = null;
while ( (line = b.readLine()) != null){
logger.info(line);
}
p.waitFor();
logger.info("COMPLETE PYTHON OUTPUT");
logger.info("EXIT VALUE: "+p.exitValue());
I can't really see any output in the catalinia.out file from the python script and using an adapter library like jython is not possible as the script relies on several machine learning libraries that need python's Numpy module to work.
Help?
The explanation is probably one (or more) of following:
The command is failing and writing error messages to its "stderr" fd ... which you are not looking at.
The command is failing to launch because the command name is incorrect; e.g. it can't be found on $PATH.
The command is trying to read from its stdin fd ... but you haven't provided any input (yet).
It could be a problem with command-line splitting; e.g if you are using pathnames with embedded spaces, or other things that would normally be handled by the shell.
Also, since this is python, this could be a problem with python-specific environment variables, the current directory and/or the effective user that is executing the command.
How to proceed:
Determine if the python command is actually starting. For instance. "hack" the "" to write something to a temporary file on startup.
Change to using ProcessBuilder to create the Process object. This will give you more control over the streams and how they are handled.
Find out what is going to the child processes "stderr". (ProcessBuilder allows you to redirect it to "stdout" ...)

Send signal from C to Java

So I have this Java program that creates processes that run a certain C program on the terminal (unix), and I need to notify the Java program when something happens in the C program (before the termination). How can I do this? I know that I'm gonna need signals, but I don't have much experience on the subject.
Thanks in advance!
EDIT: This the changes I made to the java, after calling the process:
InputStream stdout = p.getInputStream();
InputStreamReader isr = new InputStreamReader(stdout);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<INPUT>");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("</INPUT>");
int exitVal = p.waitFor();
System.out.println("Process exitValue: " + exitVal);
I what I did in the C when I want to notify the java:
char buff[20];
size_t nbytes;
ssize_t bytes_written;
int fd;
strcpy(buf, "This is a test\n");
nbytes = strlen(buf);
bytes_written = write(1, buff, nbytes);
But after running it I only get:
INPUT
/INPUT
Process exitValue: 0
One of the ways is reading your C program's stdout
Process p = Runtime.getRuntime().exec("c.exe");
InputStream stdout = p.getInputStream();
now C program can talk to Java program
You can create a socket using c program and send it to java socket server. You can search on goole to find out sample.
Easiest way to communicate between a Java program and another program spawned by it, is using the FIFO streams that are set up when you launch a subprocess. So, for example, if you launched your subprocess using Runtime.exec() or using ProcessBuilder, you have an object of type Process. By calling its getInputStream() you can have access to the process' stdout.
In the native code, just print your signals out to stdout and they can be read by the Java process.
You can use Signals with Java, but this is not the best mechanism. I would look at using JNI, JMS, Socket, RPC or some other solution first. The problem with signals is that it doesn't allow you to transmit much information and it's the easiest to get right or debug.
For more details on signal handling and Java
http://www.oracle.com/technetwork/java/javase/signals-139944.html
http://www.ibm.com/developerworks/java/library/i-signalhandling/ (link dead)
http://ringlord.com/dl/Signals-in-Java.pdf

How to display the output of an executed command line program?

I have a command line Java program which i unfortunately cannot modify for certain integrity reasons, I am providing a GUI for this program and i got it all covered except that i am unable to provide notifications about completion of processes to the user as the program prints data to command line using System.out.println() , I designed the UI using net beans and it resides in a separate file , so how can i do this..?
Are you using Runtime.exec to execute the program? Then you can get the output stream as well like this:
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("java yourOtherProgram.jar");
InputStream stdin = proc.getInputStream();
If you're calling some method directly, you could redirect System.out like this:
PrintStream out = ...;
PrintStream err = ...;
System.setOut(out);
System.setErr(err);
ThatOtherProgram foo = new ThatOtherProgram();
foo.main(new String[0]);
EDIT
You could then use the Scanner to scan the input and do something with it.

Running other programs from Java

I need to run a couple of other programs from my own Java program, basically I need to run these command line statements.
svn log --xml -v > svn.log
and
java -jar example.jar arg1 arg2
and I need to use the text outputs written to the console from these programs in my own program. I've tried Runtime.getRuntime().exec() with the svn, but it doesn't seem to be doing anything because it doesn't make a svn.log file. Also both programs need to be called in different places, the svn line needs to be called from inside one folder and the java line needs to be called from another.
Any ideas on how to go about this? If this is not possible in Java, is there a way to do it in C#?
Thanks
Here:
ProcessBuilder processbuilder
try
{
processbuilder.directory(file);
processbuilder.redirectErrorStream(true);
process = processbuilder.start();
String readLine;
BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
// include this too:
// BufferedReader output = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while((readLine = output.readLine()) != null)
{
m_Logger.info(readLine);
}
process.waitFor();
}
I've used something similar. You'll actually want to do something with the readLine. I just copied and pasted from code where I didn't care what it said.
The redirection > (like the pipe |) is a shell construct and only works when you execute stuff via /bin/sh (or equivalent). So the above isn't really going to work. You could execute
/bin/sh -c "svn log --xml -v > svn.log"
and read svn.log.
Alternatively, you can read the output from the process execution and dump that to a file (if you need to dump it to a file, or just consume it directly as you read it). If you choose this route and consume stdout/stderr separately, note that when you consume the output (stdout), you need to consume stderr as well, and concurrently, otherwise buffers will block (and your spawned process) waiting for your process to consume this. See this answer for more details.
instead of piping in your command, just let it print to standard output and error output. You can access those streams from your process object that is returned from exec.
For the svn stuff use java SVNKit API.
Seeing your two commands, why don't you do it directly from Java, without executing ? You could use SVNKit for the svn part, and include directly the jars in your classpath.
Try this
public static void main(String[] args) {
try {
// Execute a command with an argument that contains a space
System.out.println(args[0]);
String[]commands = new String[]{"svn", "info", args[0]};
Process process = Runtime.getRuntime().exec(commands);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
String result = builder.toString();
System.out.println(result);
}catch(Exception e){
System.out.print(e);
}
}

Categories