I would like the output of a shell command to go to a textArea in my java program as the shell command executes rather than after it has completed.
Current code that waits until process is complete and then shows the output:
ProcessBuilder builder = new ProcessBuilder("shell_command.sh");
builder.redirectErrorStream(true);
try {
Process p = builder.start();
String s;
BufferedReader stdout = new BufferedReader (
new InputStreamReader(p.getInputStream()));
while ((s = stdout.readLine()) != null) {
logPanel.addText(s + "\r\n"); // adds text to a textArea
}
System.out.println("Exit value: " + p.waitFor());
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
} catch (Exception ex) {
ex.printStackTrace();
}
In UI thread...
(new Thread(new ShellCommand(logPanel) ) ).start();
New Class...
class ShellCommand implements Runnable {
LogPanel logPanel; // textArea
ShellCommand(LogPanel logPanel) {
this.logPanel = logPanel;
}
public void run() {
try {
ProcessBuilder builder = new ProcessBuilder("shell_command.sh");
builder.redirectErrorStream(true);
Process p = builder.start();
String s;
BufferedReader stdout = new BufferedReader(new
InputStreamReader(p.getInputStream()));
while ((s = stdout.readLine()) != null) {
logPanel.addText(s + "\r\n");
}
System.out.println("Exit value: " + p.waitFor());
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
JOptionPane.showMessageDialog(null, "Done", "Message",
JOptionPane.INFORMATION_MESSAGE);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
Related
I'm using the following script to execute commands and get output:
Runtime rt = Runtime.getRuntime();
static Runtime rt;
static Process proc;
public static void main(String[] Args) throws IOException, InterruptedException {
rt = Runtime.getRuntime();
String[] commands = {"ssh.exe","-o BatchMode=yes", "root#192.168.1.1", "cat /var/a.txt"};
// String[] commands = {"ssh.exe", "root#192.168.0.1"};
// String[] commands = { "ls", "-la" };
proc = rt.exec(commands);
new Thread("out") {
public void run() {
System.out.println("Thread: " + getName() + " running");
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String s = null;
// read the output from the command
System.out.println("StdOut:\n");
try {
while ((s = stdInput.readLine()) != null) {
System.out.println("$ " + s);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
new Thread("err") {
public void run() {
System.out.println("Thread: " + getName() + " running");
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String s = null;
// read any errors from the attempted command
System.out.println("StdErr:\n");
try {
while ((s = stdError.readLine()) != null) {
System.out.println("! " + s);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
Thread.sleep(10000);
System.out.println("end");
}
If I execute "ls -la" or "ssh" I get the expected output. However, attempting to get a.txt content from remote device (line 1) fails and the operation hangs.
Executing "ssh root#192.168.0.1 cat a.txt" from command line works and retrieves the content.
Why is this happening? How can it be fixed?
Thanks
Because you need to read the two streams in separate threads, or merge them. You can't assume that the process will exit and therefore close its stderr before writing anything to stdtout, or rather without writing so little to stdout that it won't block.
import java.io.*;
public class Clasa {
public static void main(String args[]) {
try {
Runtime rt = Runtime.getRuntime();
String comand = "net start MySQL55";
Process pr = rt.exec(" cmd.exe /C " + "net start MySQL55");
BufferedReader input = new BufferedReader(
new InputStreamReader(pr.getInputStream()));
String line = null;
while ((line = input.readLine()) != null) {
System.out.println(line);
}
int exitVal = pr.waitFor();
System.out.println("Exited with error code " + exitVal);
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
}
I try this and gives me the next error code: Exited with error code 2
I'm fairly new to ProcessBuilder and working with threads. In it's current state I have a J-Button which starts a scheduled executor service. The scheduled executor service is used to delegate a process to one of two process builders. The application is meant to record a user conversation. During the conversation, after x minutes it creates a wav and delegates it to an available process for transcription. The problem begins when the transcription class is called. The process is started and the application runs as expected. However, the transcription process doesn't actually do anything until I exit the parent application. Only then it will begin. Checking the task manager it shows as a process but uses 0.0% of the CPU and around 238MB of memory until I exit then the two processes jump to 30%-40% and 500-1000 MB of memory. Also, I am using the .waitFor() but am using a thread to run the .waitFor() process as from what I gather it causes the application to hang. How would I go about fixing this. Sorry I am unable to provide more details but I'm new to this. Thanks in advance!
public class TranDelegator {
Future<?> futureTranOne = null;
Future<?> futureTranTwo = null;
ExecutorService transcriberOne = Executors.newFixedThreadPool(1);
ExecutorService transcriberTwo = Executors.newFixedThreadPool(1);
final Runnable transcribeChecker = new Runnable() {
public void run() {
String currentWav = null;
File inputFile = new File("C:\\convoLists/unTranscribed.txt");
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(inputFile));
} catch (FileNotFoundException e1) {
System.out.println("reader didn't initialize");
e1.printStackTrace();
}
try {
currentWav = reader.readLine();
} catch (IOException e) {
System.out.println("currentWav string issue");
e.printStackTrace();
}
try {
reader.close();
} catch (IOException e) {
System.out.println("reader couldn't close");
e.printStackTrace();
}
if(currentWav != null){
if (futureTranOne == null || futureTranOne.isDone()) {
futureTranOne = transcriberOne.submit((transcriptorOne));
}
else if (futureTranTwo == null || futureTranTwo.isDone()) {
futureTranTwo = transcriberTwo.submit((transcriptorTwo));
}
}
}
};
final Runnable transcriptorOne = new Runnable() {
public void run() {
System.out.println("ONE");
try {
String classpath = System.getProperty("java.class.path");
String path = "C:/Program Files/Java/jre7/bin/java.exe";
ProcessBuilder processBuilder = new ProcessBuilder(path, "-cp",
classpath, Transcriber.class.getName());
Process process = processBuilder.start();
try {
process.waitFor();
} catch (InterruptedException e) {
System.out.println("process.waitFor call failed");
e.printStackTrace();
}
} catch (IOException e) {
System.out.println("Unable to call transcribeConvo");
e.printStackTrace();
}
}
};
final Runnable transcriptorTwo = new Runnable() {
public void run() {
System.out.println("TWO");
try {
String classpath = System.getProperty("java.class.path");
String path = "C:/Program Files/Java/jre7/bin/java.exe";
ProcessBuilder processBuilder = new ProcessBuilder(path, "-cp",
classpath, Transcriber.class.getName());
Process process = processBuilder.start();
try {
process.waitFor();
} catch (InterruptedException e) {
System.out.println("process.waitFor call failed");
e.printStackTrace();
}
} catch (IOException e) {
System.out.println("Unable to call transcribeConvo");
e.printStackTrace();
}
}
};
}
public class Transcriber {
public static void main(String[] args) throws IOException,
UnsupportedAudioFileException {
retreiveEmpInfo();
TextoArray saveConvo = new TextoArray();
ArrayList<String> entireConvo = new ArrayList();
URL audioURL;
String currentWav = wavFinder();
ConfigReader configuration = new ConfigReader();
ArrayList<String> serverInfo = configuration
.readFromDoc("serverconfig");
while (currentWav != null) {
audioURL = new URL("file:///" + currentWav);
URL configURL = Transcriber.class.getResource("config.xml");
ConfigurationManager cm = new ConfigurationManager(configURL);
Recognizer recognizer = (Recognizer) cm.lookup("recognizer");
recognizer.allocate(); // allocate the resource necessary for the
// recognizer
System.out.println(configURL);
// configure the audio input for the recognizer
AudioFileDataSource dataSource = (AudioFileDataSource) cm
.lookup("audioFileDataSource");
dataSource.setAudioFile(audioURL, null);
// Loop until last utterance in the audio file has been decoded, in
// which case the recognizer will return null.
Result result;
while ((result = recognizer.recognize()) != null) {
String resultText = result.getBestResultNoFiller();
// System.out.println(result.toString());
Collections.addAll(entireConvo, resultText.split(" "));
}
new File(currentWav).delete();
saveConvo.Indexbuilder(serverInfo, entireConvo);
entireConvo.clear();
currentWav = wavFinder();
}
System.exit(0);
}
private static String wavFinder() throws IOException {
String currentWav = null;
int x = 1;
File inputFile = new File("C:\\convoLists/unTranscribed.txt");
File tempFile = new File("C:\\convoLists/unTranscribedtemp.txt");
BufferedReader reader = new BufferedReader(new FileReader(inputFile));
BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));
String currentLine = null;
String newLine = System.getProperty("line.separator");
while ((currentLine = reader.readLine()) != null) {
if (x == 1) {
currentWav = currentLine;
} else {
writer.write(currentLine);
writer.write(newLine);
}
x = 2;
}
reader.close();
writer.flush();
writer.close();
inputFile.delete();
// boolean successful =
tempFile.renameTo(inputFile);
// System.out.println("Success: " + successful);
// System.out.println("currentWav = " + currentWav);
return currentWav;
}
private static void retreiveEmpInfo() throws IOException {
File tempFile = new File("C:\\convoLists/tmp.txt");
BufferedReader reader = new BufferedReader(new FileReader(tempFile));
CurrentEmployeeInfo.setName(reader.readLine());
CurrentEmployeeInfo.setUserEmail(reader.readLine());
CurrentEmployeeInfo.setManagerEmail(reader.readLine());
reader.close();
}
}
This problem may be related to sub-process's input stream buffers.
You should clear the sub-process's input stream buffers.
These stream buffers got increased within the parent process's memory with time and at some moment your sub-process will stop responding.
There are few options to make sub-process work normally
Read continuously from sub-process's input streams
Redirect sub-process's input streams
Close sub-process's input streams
Closing sub-process's input streams
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
InputStream inStream = process.getInputStream();
InputStream errStream = process.getErrorStream();
try {
inStream.close();
errStream.close();
} catch (IOException e1) {
}
process.waitFor();
Reading sub-process's input streams
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
InputStreamReader tempReader = new InputStreamReader(new BufferedInputStream(p.getInputStream()));
final BufferedReader reader = new BufferedReader(tempReader);
InputStreamReader tempErrReader = new InputStreamReader(new BufferedInputStream(p.getErrorStream()));
final BufferedReader errReader = new BufferedReader(tempErrReader);
try {
while ((line = reader.readLine()) != null) {
}
} catch (IOException e) {
}
try {
while ((line = errReader.readLine()) != null) {
}
} catch (IOException e) {
}
process.waitFor();
Redirecting sub-process's input streams
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectInput();
processBuilder.redirectError();
Process process = processBuilder.start();
process.waitFor();
(from comments)
Looks like process hang is due to out/error streams becoming full. You need to consume these streams; possibly via a thread.
Java7 provides another way to redirect output.
Related : http://alvinalexander.com/java/java-exec-processbuilder-process-3
I have a rather complex application that I'm trying to create for an android phone. I have a class that uses the Java Process Builder and some private classes to read from both the input and output streams.
At times when the IP I'm trying to ping does not respond the thread locks due to the process getting stuck, the executor service decides after 2 minutes to shutdown. This avoids the entire application locking but the two streams never close and the threads for the streams stay open.
Any idea how to kill the stream threads?
class StreamGobbler extends Thread {
InputStream is;
String type;
StreamGobbler(InputStream is, String type) {
this.is = is;
this.type = type;
}
public void run() {
InputStreamReader isr = new InputStreamReader(is);
try {
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null){
System.out.println(type + ">" + line);
}
} catch (IOException e) {
LogWriter.getInstance().writeToLogFile(e);
}finally{
try {
if(is != null){
is.close();
}
if(isr != null){
isr.close();
}
} catch (IOException e) {
LogWriter.getInstance().writeToLogFile(e);
}
}
}
public void kill() {
Thread.currentThread().interrupt();
}
}
public class PingRunner implements Callable<Double>{
private String pingVal;
private int exitVal;
private double laten;
private String ipAddress;
public PingRunner(String ipAddress) {
pingVal = "";
exitVal = -1;
laten = -1;
this.ipAddress = ipAddress;
}
#Override
public Double call() throws Exception {
List<String> commands = new ArrayList<String>();
commands.add("ping");
commands.add("-c");
commands.add("5");
commands.add(ipAddress);
try {
this.doCommand(commands);
} catch (IOException e) {
LogWriter.getInstance().writeToLogFile(e);
}
return laten;
}
private void doCommand(List<String> command) throws IOException{
ProcessBuilder pb = new ProcessBuilder(command);
Process process = pb.start();
// any error message?
StreamGobbler errorGobbler = new StreamGobbler(
process.getErrorStream(), "ERROR");
// any output?
OutputStreamGobbler outputGobbler = new OutputStreamGobbler(
process.getInputStream(), "OUTPUT");
// kick them off
errorGobbler.start();
outputGobbler.start();
// read the output from the command
try {
exitVal = process.waitFor();
//Sleep for 10 secs to try to clear the buffer
Thread.sleep(10000);
//pingVal = echo.toString();
if(exitVal == 0 && !pingVal.isEmpty()){
//System.out.println("PING STATS: "+pingVal);
try{
pingVal = pingVal.substring(pingVal.lastIndexOf("rtt min/avg/max/mdev"));
pingVal = pingVal.substring(23);
pingVal = pingVal.substring(pingVal.indexOf("/")+1);
laten = Double.parseDouble(pingVal.substring(0,pingVal.indexOf("/")));
}catch (IndexOutOfBoundsException e){
System.out.println("PING VAL: "+ pingVal);
LogWriter.getInstance().writeToLogFile(e);
}
}
} catch (InterruptedException e) {
LogWriter.getInstance().writeToLogFile(e);
errorGobbler.kill();
outputGobbler.kill();
}finally{
errorGobbler = null;
outputGobbler = null;
}
System.out.println("ExitValue: " + exitVal);
}
In my main class I have this method:
protected void ping() {
laten = -1;
serverIP = serverIPs.get(testIndex % 3);
PingRunner pRunner = new PingRunner(serverIP);
Set<Callable<Double>> runner = new HashSet<Callable<Double>>();
runner.add(pRunner);
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
laten = executor.submit(pRunner).get(2, TimeUnit.MINUTES);
executor.shutdown();
} catch (InterruptedException e) {
LogWriter.getInstance().writeToLogFile(e);
} catch (ExecutionException e) {
LogWriter.getInstance().writeToLogFile(e);
} catch (CancellationException e) {
pRunner.kill();
executor.shutdown();
LogWriter.getInstance().writeToLogFile(e);
LogWriter.getInstance().writeToLogFile(
"ERROR: Unable to ping server: " + serverIP);
} catch (TimeoutException e) {
pRunner.kill();
executor.shutdown();
LogWriter.getInstance().writeToLogFile(e);
LogWriter.getInstance().writeToLogFile(
"ERROR: Unable to ping server: " + serverIP);
} finally {
executor = null;
System.gc();
}
Any idea how to kill the stream threads?
Not sure what is going on but one bug I see is:
public void kill() {
Thread.currentThread().interrupt();
}
That is interrupting the caller thread, not the gobbler thread. That should be:
public void kill() {
// kill the gobbler thread
interrupt();
}
This is true since the StreamGobbler extends Thread. As always, it is recommended that you implements Runnable and then have a private Thread field if necessary. Then you would do something like thread.interrupt();.
Also, you are not closing your streams correctly. Typically, when I wrap one stream in another, I set the wrapped stream to be null. Also, you are not closing the br BufferedReader. The code should be:
InputStreamReader isr = new InputStreamReader(is);
is = null;
BufferedReader br = null;
try {
br = new BufferedReader(isr);
isr = null;
String line = null;
...
} finally {
// IOException catches not listed
if(br != null){
br.close();
}
if(isr != null){
isr.close();
}
if(is != null){
is.close();
}
}
I'm a big fan of the org.apache.commons.io.IOUtils package that has the closeQuietly(...) method that turns the finally block into:
IOUtils.closeQuietly(br);
IOUtils.closeQuietly(isr);
IOUtils.closeQuietly(is);
I am getting into the Defunct zombie process whenever the below code is executed. Could someone help me to resolve this issue.
private static boolean executeCommand(String command)
throws ClientException, IOException, InterruptedException {
int exitVal = 1; // 0 is success, so we default to a nonzero.
Process proc = null;
try{
Runtime rt = Runtime.getRuntime();
proc = rt.exec(command);
//Below lines are required to flush out the streams. else the process will hang.
ReadStream s1 = new ReadStream("stdin", proc.getInputStream ());
ReadStream s2 = new ReadStream("stderr", proc.getErrorStream ());
s1.start ();
s2.start ();
exitVal = proc.waitFor();
if (exitVal == 0) {
return true;
} else {
throw new ClientException("103", "" + command + " failed.");
}
}finally{
if(proc != null){
proc.destroy();
}
}
}
I am clearing all the streams in separate threads.
Here is my ReadStream class
public class ReadStream implements Runnable {
private static Logger logger = Logger.getLogger(ReadStream.class);
String name;
InputStream is;
Thread thread;
public ReadStream(String name, InputStream is) {
this.name = name;
this.is = is;
}
public void start() {
thread = new Thread(this);
thread.start();
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
while (true) {
String s = br.readLine();
if (s == null)
break;
logger.info("[" + name + "] " + s);
}
is.close();
} catch (Exception ex) {
logger.error("Problem reading stream " + name + "... :" + ex);
}
}
}
I dont think this is the problem but try to change the run methode to:
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
do {
String s = br.readLine();
if (s != null)
logger.info("[" + name + "] " + s);
} while (s != null);
is.close();
} catch (Exception ex) {
logger.error("Problem reading stream " + name + "... :" + ex);
}