Java Process stops in the middle of the process - java

I've been trying to google this around for quite a while now, without any success. I'm hoping to get my issue solved here.
First function:
public void startTFServer(Channel c) {
try {
ProcessBuilder procBuilder = new ProcessBuilder("tfs.exe");
procBuilder.redirectErrorStream();
Process proc = null;
System.out.println(Runtime.getRuntime().freeMemory());
proc = procBuilder.start();
System.out.println(Runtime.getRuntime().freeMemory());
StreamGobbler gobbler = new StreamGobbler(proc.getInputStream(), "STD_OUT");
gobbler.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The thread that captures the process output:
private class StreamGobbler extends Thread {
InputStream is;
String type;
private StreamGobbler(InputStream is, String type) {
this.is = is;
this.type = type;
}
#Override
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(type + "> " + line);
}
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
The problem:
When running the application the input interrupts at the same place every time. The application I'm running with the "Process class" is a server that required quite some memory to run, can this be one of the reasons for why the process won't finish loading my app? I was thinking that the memory would run out, but I can't really diagnostise it.
Any help would be greatly appreciated!

There is one issues that I notice:
procBuilder.redirectErrorStream();
This is not what you want. This is a getter method which tells you what the value of the redirectErrorStream property is. It could possibly be that you have errors and you are blocked because they are not read. Therefore, you need to use the setter method: see the API redirectErrorStream(boolean)
procBuilder.redirectErrorStream(true);

I'm guessing so sorry if I'm wrong, but I think you are exhausting the output from the external process, not waiting until it finishes in order to keep reading. I mean, basically:
while ((line = br.readLine()) != null) {
System.out.println(type + "> " + line);
}
If the process stops writing to the output for a second, your logger will stop logging. If it starts writing again, you will be out of the loop.

Related

Starting external application inside Java

I'm having trouble starting an application from my JavaFX GUI. I'm using ProcessBuilder. It creates the process, but the application won't launch until I close my Java program. Is it because that specific program is waiting for arguments or something wrong with my code?
#FXML
private void runWorldpac() {
try {
ProcessBuilder process = new ProcessBuilder("C:\\speedDIAL\\speedDIAL.exe");
Process p = process.start();
} catch (IOException e) {
e.printStackTrace();
}
}
External application starts but won't allow any interaction with the original application until i close this external program. Tried running a new thread, same result.
Here's the new code:
try {
ProcessBuilder process = new ProcessBuilder("C:\\speedDIAL\\speedDIAL.exe");
Map<String, String> environ = process.environment();
Process p = process.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);
}
System.out.println("Program terminated!");
} catch (IOException e) {
e.printStackTrace();
}
Read that article, good info. Also read another good example on here. It's running in a new thread now, but my program is waiting for the external application to finish before it continues, I understand that's usually desired, but not in this case, how can i disable that?
Wait for the production of the exit value in a new thread. Something like:
try {
ProcessBuilder pBuilder = new ProcessBuilder("C:\\speedDIAL\\speedDIAL.exe");
// don't forget to handle the error stream, and so
// either combine error stream with input stream, as shown here
// or gobble it separately
pBuilder.redirectErrorStream(true);
final Process process = pBuilder.start();
final InputStream is = process.getInputStream();
// in case you need to send information back to the process
// get its output stream. Don't forget to close when through with it
final OutputStream os = process.getOutputStream();
// thread to handle or gobble text sent from input stream
new Thread(() -> {
// try with resources
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is));) {
String line = null;
while ((line = reader.readLine()) != null) {
// TODO: handle line
}
} catch (IOException ex) {
ex.printStackTrace();
}
}).start();
// thread to get exit value from process without blocking
Thread waitForThread = new Thread(() -> {
try {
int exitValue = process.waitFor();
// TODO: handle exit value here
} catch (InterruptedException e) {
e.printStackTrace();
}
});
waitForThread.start();
// if you want to join after a certain time:
long timeOut = 4000;
waitForThread.join(timeOut);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}

Freezing window when using multithread in java

I've got a gui in java and I want to run inside my GUI when a button is pressed one executable. My code for running the executable is the following:
Process pr;
Runtime rt = Runtime.getRuntime();
new Thread(() -> {
try {
Process proc = rt.exec("Release\\face.exe", null, new File("Release\\"));
} catch (Exception e1) {
e1.printStackTrace();
}
}).start();
The executable is running when I am pressing the button however I detect a freezing in the executable behavior. I tried to add multithreading to check if that is the reason for freezing, however still I am experienced the same thing. What could be wrong here?
EDIT:
I tried to add the following lines for inputStreamReader inside my thread:
new Thread(() -> {
try {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("face.exe", null, new File("Release\\"));
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader err = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}).start();
I got the message InputStreamReader cannot be resolved to a type.
As bowmore mentioned, your executable likely blocks because the output is not handled and "gets stuck" after a while as the executable cannot write more to its standard out (likely the console).
I usually use code like the following to run external commands from java:
Process p = Runtime.getRuntime().exec(args);
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream()));
StreamHandler outputHandler = new StreamHandler(in);
outputHandler.start();
StreamHandler errorHandler = new StreamHandler(err);
errorHandler.start();
where StreamHandler is defined as follows:
class StreamHandler extends Thread {
private final BufferedReader in;
private final JTextArea[] textArea;
public StreamHandler(final BufferedReader in) {
this.in = in;
}
#Override
public void run() {
try {
String line = null;
while ((line = this.in.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
log.info("StreamHandler got interrupted");
e.printStackTrace();
}
}
}
Naturally, the stream handler could be more sophisticated, e.g. write errors to System.err instead of System.out, or to write to a JTextArea, or somewhere else.
Since you don not read the InputStreams for this process object, it is possible that it's stuck because the stream's buffer is full, causing the exe to block on the write to stdout.

Process started from Java hangs

I am trying to execute a c++ code from java on a remote Windows machine. In order to deal with the remote part, I have created a Web service from where the actual command is run using Runtime.exec(). The c++ exe is not being called directly from the java code. I have a batch file that eventually calls the exe.
The problem is, both java and c++ processes hang. The java code on server side does handle the output stream and error stream. Also, the c++ code is logging everything in a file on Windows. The strange thing is that, when I remove the WS call and run the java code on server side as a standalone java program, it succeeds. Here is the java code:
public class RunCPlusPlusExecutable {
public int runExecutable() {
int exitValue = 0;
try {
Process p = null;
Runtime rt = Runtime.getRuntime();
System.out.println("About to execute" + this + rt);
p = rt.exec("c:/temp/execcplusplus.bat");
System.out.println("Process HashCode=" + p.hashCode());
StreamProcessor errorHandler = new StreamProcessor(p.getErrorStream(), "Error");
StreamProcessor outputHandler = new StreamProcessor(p.getInputStream(), "Output");
errorHandler.start();
outputHandler.start();
exitValue = p.waitFor();
System.out.println("Exit value : " + exitValue);
if (exitValue == 0)
System.out.println("SUCCESS");
else
System.out.println("FAILURE");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
}
return exitValue;
}
class StreamProcessor extends Thread {
private InputStream is = null;
private String type = null;
private InputStreamReader isr = null;
private BufferedReader br = null;
private FileWriter writer = null;
private BufferedWriter out = null;
StreamProcessor(InputStream is, String type) {
this.is = is;
this.type = type;
}
public void run() {
try {
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
writer = new FileWriter("*******path to log file********");
out = new BufferedWriter(writer);
String line = null;
while ((line = br.readLine()) != null) {
Date date = new Date();
out.write("[" + type + "]: " + date + " : " + line);
out.newLine();
}
writer.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if (br != null)
br.close();
if (isr != null)
isr.close();
if (out != null)
out.close();
if (writer != null)
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Any idea what is causing the problem and how to debug it? Please note that I won't be able to debug the c++ code.
Thanks
Update 1:
Here are some more details...
The WS server is running from some admin user. And I have been running the standalone java program from some other user.
*It seems that the c++ executable is giving referenced memory error while executing from WS call. There are pop-ups citing the error with OK and Cancel buttons. *
Update 2:
The tomcat server where the WS is deployed is running as a Windows NT service. Can that be the cause of the error? If yes, how to resolve this?

Cannot get the getInputStream from Runtime.getRunTime.exec()

public class LinuxInteractor {
public static String executeCommand(String command)
{
System.out.println("Linux command: " + command);
try
{
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader bf=new BufferedReader(new InputStreamReader( p.getInputStream()));
String str=bf.readLine();
System.out.println("inputStream is::"+str);
while( (str=bf.readLine()) != null)
{
System.out.println("input stream is::"+str);
}
System.out.println("process started");
}
catch (Exception e) {
System.out.println("Error occured while executing Linux command. Error Description: "
+ e.getMessage());
e.printStackTrace();
}
}
When I run the script through console, it's working. But through Java program InputStream(Str) is coming as null.
Is there any other approach I can use?
Solution
You should try to do the reading and the executing on different threads.
A better alternative is to use a ProcessBuilder, which takes care of the "dirty" work for you.
The code inside the try block could look something like this:
/* Create the ProcessBuilder */
ProcessBuilder pb = new ProcessBuilder(commandArr);
pb.redirectErrorStream(true);
/* Start the process */
Process proc = pb.start();
System.out.println("Process started !");
/* Read the process's output */
String line;
BufferedReader in = new BufferedReader(new InputStreamReader(
proc.getInputStream()));
while ((line = in.readLine()) != null) {
System.out.println(line);
}
/* Clean-up */
proc.destroy();
System.out.println("Process ended !");
See, also, this short demo.
Cause of the problem
According to the Java Docs, waitFor():
causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
So, you are trying to get the process's output-stream after it has terminated, therefore the null.
(Sorry for the major revamp of the answer.)
You need to do this in a separate thread:
Process process = Runtime.getRuntime().exec(command);
LogStreamReader lsr = new LogStreamReader(process.getInputStream());
Thread thread = new Thread(lsr, "LogStreamReader");
thread.start();
public class LogStreamReader implements Runnable {
private BufferedReader reader;
public LogStreamReader(InputStream is) {
this.reader = new BufferedReader(new InputStreamReader(is));
}
public void run() {
try {
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then you need a second thread for input handling. And you might want to deal with stderr just like stdout.

Runtime.exec() won't finish properly

I've created a WebApp that relies on external scripts to gather query request by the user (internal software). I've tested, with sucess, the WebApp off the glassfish server provided by netbeans but whenever I try and upload my App to a third party server (Apache Tomcat) I run into the issue of the process.getRuntime exitValue never being written and the WebApp never gets to the result page....
This is the code that I have implemented so far:
Update --> The code now works after reading both stderr and stdin:
pd = new ProcessBuilder("runscript.bat");
pd.redirectErrorStream(true);
process = pd.start();
StreamGobbler inputGobbler = new StreamGobbler(process.getInputStream(), "Input");
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(),"Error");
errorGobbler.start();
inputGobbler.start();
int exitVal = -1;
try {
exitVal = process.waitFor();
} catch (InterruptedException ex) {
//log Error
}
class StreamGobbler extends Thread {
OutputWriterReader outWR = new OutputWriterReader();
BufferedWriter deadWriter;
InputStream is;
// reads everything from is until empty.
StreamGobbler(InputStream is, String type) {
this.is = is;
createWatch(type);
}
// depending on if Error stream or Input Stream
private void createWatch(String type){
try {
if(type.equals("Error"))
deadWriter = new BufferedWriter(new FileWriter("StdError.txt"));
else if(type.equals("Input"))
deadWriter = new BufferedWriter(new FileWriter("StdInput.txt"));
} catch (IOException ex) {
//log Error
}
}
#Override
public void run() {
try {
InputStreamReader isr = new InputStreamReader(this.is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null)
deadWriter.append(line);
deadWriter.flush();
deadWriter.close();
} catch (IOException ioe) {
//log Error
}
}
}
Any Suggerstions? Thanks in advance for any help
The process may not be complete when you call exitValue() on it.
Before process.exitValue() call add:
process.waitFor();

Categories