I need to extract the input stream of the process after I start it.
Today I can get the initial information but the method doesn't return until I close the application (in this case the application started by the process: gedit and firefox). I mean, I know it just return after I close the process, but I'd like to have a workaround to get that prior to the process closing.
See my code below.
public class ProcessInvokerExtractingProcessInformation {
public static void main(String args[]) {
try {
Process pOpenApp = new ProcessBuilder(new String[] { "gedit",
"/home/thais/Documents/gedit_doc1" }).start();
printInformation("pOpenApp", pOpenApp);
// * just for testing error message and input stream
Process openFirefox = new ProcessBuilder(new String[] { "firefox" })
.start();
printInformation("lsInstruction", openFirefox);
deleteProcess(pOpenApp);
deleteProcess(openFirefox);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// method for testing information we can see regarding the process
public static void printInformation(String id, final Process process) {
System.out.println(" Process " + id + ":");
//tried to run in a separated thread but didn't work as well
Runnable r = new Runnable(){
public void run(){
System.out.print("\n Process error message -> ");
printScannedStream(process.getErrorStream());
System.out.println("\n Process input message -> ");
printScannedStream(process.getInputStream());
}
};
Thread a = new Thread(r);
a.start();
/* other approaches to print the streams, tried before
StringWriter writer = new StringWriter();
try {
PrintWriter pWriter = new PrintWriter(new
BufferedOutputStream(process.getOutputStream()));
pWriter.write("Hi"); pWriter.flush(); System.out.println(
" Process output stream is for writing so there is no information "
);
*//*
InputStreamReader isr = new InputStreamReader(
process.getErrorStream());
BufferedReader br = new BufferedReader(isr);
System.out.print("\n Process error message -> ");
while (br.readLine() != null) {
System.out.print(br.readLine());
}
System.out.println("\n Process input message -> ");
isr = new InputStreamReader(process.getInputStream());
br = new BufferedReader(isr);
while (br.readLine() != null) {
System.out.print(br.readLine());
}
br.close();
isr.close();*/
/*
* IOUtils.copy(process.getErrorStream(), writer, null);
* System.out.println(" Process error message -> " +
* writer.toString());
*
* IOUtils.copy(process.getInputStream(), writer, null);
* System.out.println(" Process input stream message -> " +
* writer.toString()+"\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
*/
}
/**
* Method that close all streams and after destroy the process It's
* important to close the streams to avoid file descriptions leaking
*
* #param process
*/
public static void deleteProcess(Process process) {
try {
process.getInputStream().close();
process.getOutputStream().close();
process.getErrorStream().close();
process.destroy();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void printScannedStream(java.io.InputStream is) {
try {
Scanner scanner = new Scanner(is);
while(scanner.hasNext()) {
System.out.print(scanner.next());
}
} catch (java.util.NoSuchElementException e) {
e.printStackTrace();
}
}
}
I had the same problem and I solved it with using an additional thread.
class InputHandler implements Runnable {
InputStream input_;
InputHandler(InputStream input) {
input_ = input;
}
public void run() {
try {
int c;
String line = "";
while ((c = input_.read()) != -1) {
if (((char) c == '\r') || ((char) c == '\n')) {
if (!line.isEmpty()) flushString(line);
line = "";
} else
line += (char) c;
}
} catch (Throwable t) {
t.printStackTrace();
}
}
private void flushString(String s) {
// any code to process data from stream
Logger.debug("library: " + getClass().getName() + ": compress: output: " + s);
}
}
Process process = run.exec(ffmpegCmdString);
// read output
InputHandler stderrHandler = new InputHandler(process.getErrorStream());
new Thread(stderrHandler).start();
InputHandler stdoutHandler = new InputHandler(process.getInputStream());
new Thread(stdoutHandler).start();
process.waitFor();
Related
I want a solution for printing value of process variable p. How can we print value of p? Currently value of p is: java.lang.UNIXProcess#727896
public class shellscript{
public static void main(String[] args) {
Runtime r = Runtime.getRuntime();
Process p = null;
String cmd[] = {
"/bin/bash",
"/home/aminul/myscript"
};
try {
p = r.exec(cmd);
System.out.println("testing..." + p);
System.out.println(p);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
If you want to log the standard output and the exit code of the process, try the following:
public static void main(String[] args) throws Exception
{
final Runtime r = Runtime.getRuntime();
final String cmd[] = { "/bin/bash", "/home/aminul/myscript" };
try
{
final Process p = r.exec(cmd);
new Thread()
{
public void run()
{
BufferedReader br = null;
try
{
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = br.readLine();
while (line != null)
{
System.out.println(line);
line = br.readLine();
}
}
catch (final Exception e)
{
e.printStackTrace();
}
finally
{
if (br != null)
try
{
br.close();
}
catch (final IOException ioe)
{
ioe.printStackTrace();
}
}
};
}.start();
p.waitFor();//wait for process to terminate
System.out.println("Exit code: "+p.exitValue());
}
catch (Exception e)
{
e.printStackTrace();
}
}
Of course, if you want to log the ErrorStream as well, you will have to start another thread.
Process don't have name attribute. But you can use pid.
You can try it in this way
Field field=p.getClass().getField("pid"); // use reflection since pid is private
System.out.println(field);
But you can't use
System.out.println(p)
Since Process don't have a override toString() method
I am just trying to control processbuilder inputstream and outputstream from different class
It is main class
public class Controller
{
public static void main(String[]args)
{
Runner r=new Runner("Test");
r.activateInput();
r.setInput("Test");
}
}
It is other class to run process
import java.io.*;
public class Runner
{
boolean activeInput=true;
boolean active=true;
String input;
public Runner(String command)
{
try {
// create a new process
System.out.println("Creating Process...");
ProcessBuilder compile = new ProcessBuilder("java","TestOut");
compile.directory(new File("C:/Users/abhishek221192/Documents/Socket"));
Process process = compile.start();
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
InputStream stdout = process.getInputStream ();
final BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
BufferedReader error = new BufferedReader (new InputStreamReader(stderr));
final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
//final Scanner scan=new Scanner(System.in);
Thread T=new Thread(new Runnable() {
#Override
public void run() {
while(active)
{
if(activeInput)
System.out.println(activeInput+" "+input);
String data ="Abhi";
data += "\n";
try {
if(activeInput){
writer.write(data);
writer.flush();
activeInput=false;
}
//
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} );
T.start();
T.setName("Input");
Thread T1=new Thread(new Runnable() {
#Override
public void run() {
String line;
try{
while ((line = reader.readLine ()) != null) {
System.out.println(line);
}} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} );
T1.start();
T1.setName("Output");
/*
String line;
while ((line = error.readLine ()) != null) {
System.out.println(line);
}
*/
//stdout.close();
//error.close();
//T.stop();
//stdin.close();
//System.err.println("stdin closed");
active=false;
// close the output stream
System.out.println("Closing the output stream...");
//testProcessBuilder();
} catch (Exception ex) {
System.out.println("Error"+ex.getMessage());
}
}
public void activateInput()
{
this.activeInput=true;
System.out.println("active"+activeInput);
}
public void setInput(String input)
{
this.input=input;
}
}
It is TestOut code it include only one input statement
TestOut.java
import java.util.*;
public class TestOut
{
public static void main(String[]args)
{
Scanner sc=new Scanner(System.in);
System.out.println("Output hello TestOut");
System.out.println("Output1 "+sc.nextLine());
}
}
I am geting this output
Creating Process...
true null
Closing the output stream...
activetrue
Output hello TestOut
Output1 Abhi
r.setInput(); is not setting value
Couple of changes i made to make it work. the main problem with this piece of code is concurrency issues as two threads are working on same set of data. activeInput is being modified by Controller and by thread T
Change 1:
public synchronized void activateInput(boolean activate) {
this.activeInput = activate;
System.out.println("active" + activeInput);
}
if (activeInput) {
writer.write(data);
writer.flush();
activateInput(false);
}
declared method activateInput synchronized and replaced activateInput = false with the method call in thread T
Change 2:
// active = false;
commented out this line at the end of Runner() method because it is stopping the writer Thread unnecessarily.
Change 3:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Added this at the end of Writer Thread's while loop to give writer Thread T some breathing space and to give it a chance on reading the values.
Output:
Here is the output i got:
Creating Process...
activetrue
Output hello TestOut
true Test
activefalse
Output1 Abhi
Hope this helps.
I have to build a chat program.
There is the server class, the client class and two threads to write and receive messages.
the two threads should run in an infinite loop and check all the time if there is an input and print that input afterwards.
But my program works for just one round. So the server and the client can write one single message, afterwards it stops and does not check for another message. Why does the thread not start again from the begin when it's never interrupted? --> see the code beneath
I hope you know what my problem is, it's quite hard for me to describe.
Thread to read a new Message
public class MsgWriter extends Thread {
private Socket s;
public MsgWriter(Socket s){
this.s = s;
}
public void run(){
int i = 0;
OutputStream out = null;
PrintWriter writer;
Scanner input;
while(!interrupted()){
try{
synchronized(s){
input = new Scanner (System.in);
out = s.getOutputStream();
writer = new PrintWriter(out);
String toserver = input.nextLine();
writer.write(toserver);
writer.flush();
System.out.println("me: " + toserver);
}
try {
Thread.sleep((int) (100 * Math.random()));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}catch(Exception e) {
}
}
}
}
Thread to check if there is a new message and prints it.
public class MsgReader extends Thread {
Socket s;
public MsgReader(Socket s){
this.s = s;
}
public void run() {
int i = 0;
while (!interrupted()) {
try{
synchronized(s){
InputStream in = s.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String s = null;
while((s=reader.readLine()) != null){
System.out.println("d");
}
}
try {
Thread.sleep((int) (100 * 1));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}catch (Exception e){
}
}
}
}
The Server class starts a new server and waits for a client, afterwards it starts the two threads. The same with the client class, it connects to the server and starts the threads.
You're probably thowing an exception somewhere. In your catch blocks, print the error.
try {
} catch (Exception e) {
System.out.println("Error: " + e);
}
I have the following snippet of code:
Process proc = runtime.exec(command);
errorGobbler = new ErrorStreamGobbler(proc.getErrorStream(), logErrors, mdcMap);
outputGobbler = new OutputStreamGobbler(proc.getInputStream(), mdcMap);
executor.execute(errorGobbler);
executor.execute(outputGobbler);
processExitCode = proc.waitFor();
where the gobblers are Runnables which use a BufferedReader to read the input and error streams of the executing process. While this works most of the time, I get the occasional window (of about 2 minutes or so) where I get the processExitCode as 0, which indicates normal termination but there is nothing in the input and error streams - nothing to even indicate end-of-stream.
Like I indicated before, this works most of the time but this failure occurs every once in a while - and I am totally puzzled. Any ideas?
Rags
I've struggled with the same kind of issues.
I can't remember what exactly was wrong (maybe I forgot to flush / close the streams correctly or something ...).
Anyway, here is what I came up with.
/**
* Handle communication with a process, reading its output/error and feeding its input
* #param process The process to execute
* #param _in Reader that will feed the input pipe of the process
* #param out Writer that will receive the output of the process
* #param err Writer that will receive the error pipe of the process
*/
public static void communicate(
Process process,
final Reader _in,
final Writer out,
final Writer err)
{
// Buffer the input reader
final BufferedReader in = new BufferedReader(_in);
// Final versions of the the params, to be used within the threads
final BufferedReader stdOut = new BufferedReader(new InputStreamReader(process.getInputStream()));
final BufferedReader stdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
final BufferedWriter stdIn = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
// Thread that reads std out and feeds the writer given in input
new Thread() {
#Override public void run() {
String line;
try {
while ((line = stdOut.readLine()) != null) {
out.write(line + newline);
}
} catch (Exception e) {throw new Error(e);}
try {
out.flush();
out.close();
} catch (IOException e) { /* Who cares ?*/ }
}
}.start(); // Starts now
// Thread that reads std err and feeds the writer given in input
new Thread() {
#Override public void run() {
String line;
try {
while ((line = stdErr.readLine()) != null) {
err.write(line + newline);
}
} catch (Exception e) {throw new Error(e);}
try {
err.flush();
err.close();
} catch (IOException e) { /* Who cares ?*/ }
}
}.start(); // Starts now
// Thread that reads the std in given in input and that feeds the input of the process
new Thread() {
#Override public void run() {
String line;
try {
while ((line = in.readLine()) != null) {
stdIn.write(line + newline);
}
} catch (Exception e) {throw new Error(e);}
try {
stdIn.flush();
stdIn.close();
} catch (IOException e) { /* Who cares ?*/ }
}
}.start(); // Starts now
// Wait until the end of the process
try {
process.waitFor();
} catch (Exception e) {
throw new Error(e);
}
} // End of #communicate
I hope this helps.
I'm trying to enter some value in external application using Java.
Java application looks like this:
Runtime runtime = Runtime.getRuntime();
// ... str build ...
proc = runtime.exec(str);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
bw.write(value);
bw.flush();
bw.close();
if (proc.waitFor() != 0)
// error msg
// the end
Application hangs at waitFor method.
External application looks like this:
welcome banner
please enter 8 character input:
Welcome banner is printed using printf and input is taken with SetConsoleMode/ReadConsoleInput. ReadConsoleInput reads one char and they are masked with * character.
Help
you can use:
proc.getOutputStream().write("some date".getBytes())
keep in mind that you HAVE to read everything the app send to stdout and stderr, else it might get stuck writing there.
I use a generic class to read it in a different thread.
usage is like:
InputStreamSucker inSucker = new InputStreamSucker(proc.getInputStream());
InputStreamSucker errSucker = new InputStreamSucker(proc.getErrorStream());
proc.waitFor();
int exit = process.exitValue();
inSucker.join();
errSucker.join();
InputStreamSucker code is here:
public class InputStreamSucker extends Thread
{
static Logger logger = Logger.getLogger(InputStreamSucker.class);
private final BufferedInputStream m_in;
private final ByteArrayOutputStream m_out;
private final File m_outFile;
public InputStreamSucker(InputStream in) throws FileNotFoundException
{
this(in, null);
}
public InputStreamSucker(InputStream in, File outFile) throws FileNotFoundException
{
m_in = new BufferedInputStream(in, 4096);
m_outFile = outFile;
m_out = new ByteArrayOutputStream();
start();
}
#Override
public void run()
{
try
{
int c;
while ((c = m_in.read()) != -1)
{
m_out.write(c);
}
}
catch (IOException e)
{
logger.error("Error pumping stream", e);
}
finally
{
if (m_in != null)
{
try
{
m_in.close();
}
catch (IOException e)
{
}
}
try
{
m_out.close();
}
catch (IOException e)
{
logger.error("Error closing out stream", e);
}
if (m_outFile != null)
{
byte data[] = m_out.toByteArray();
if (data.length > 0)
{
FileOutputStream fo = null;
try
{
fo = new FileOutputStream(m_outFile);
fo.write(data);
}
catch (IOException e)
{
logger.error("Error writing " + m_outFile);
}
finally
{
try
{
if (fo != null) fo.close();
}
catch (IOException e)
{
logger.error("Error closing " + m_outFile);
}
}
}
}
}
}
public String getOutput()
{
return new String(m_out.toByteArray());
}
}
Got the answer! The trick is to use WriteConsoleInput() API because program expects keyboard event, not text ... That's why the waitFor() waited forever! :)