I have the following code and I can't figure out why it won't work:
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final String p1 = "HELLO WORLD";
process(p1, bos);
Assert.assertEquals("BOS value should be: "+p1, p1, bos.toString("UTF-8"));
It prints:
junit.framework.ComparisonFailure: BOS value should be: HELLO WORLD expected:<[HELLO WORLD]> but was:<[]>
at junit.framework.Assert.assertEquals(Assert.java:81) etc...
and process looks like this:
public static void process(final String p1, final OutputStream os) {
final Runtime rt = Runtime.getRuntime();
try {
final String command = "echo " + p1;
log.info("Executing Command: " + command);
final Process proc = rt.exec(command);
// gobble error and output
StreamGobbler.go(proc.getErrorStream(), null);
StreamGobbler.go(proc.getInputStream(), os);
// wait for the exit
try {
final int exitVal = proc.waitFor();
log.info("Command Exit Code: " + exitVal);
} catch (InterruptedException e) {
log.error("Interrupted while waiting for command to execute", e);
}
} catch (IOException e) {
log.error("IO Exception while executing command", e);
}
}
private static class StreamGobbler extends Thread {
private final InputStream is;
private final OutputStream os;
private static StreamGobbler go(InputStream is, OutputStream os) {
final StreamGobbler gob = new StreamGobbler(is, os);
gob.start();
return gob;
}
private StreamGobbler(InputStream is, OutputStream os) {
this.is = is;
this.os = os;
}
public void run() {
try {
final PrintWriter pw = ((os == null) ? null : new PrintWriter(os));
final InputStreamReader isr = new InputStreamReader(is);
final BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
if (pw != null) {
pw.println(line);
}
log.info(line); // Prints HELLO WORLD to log
}
if (pw != null) {
pw.flush();
}
} catch (IOException ioe) {
log.error("IO error while globbing", ioe);
}
}
When I run the jUnit test I get an empty string as the actual. I don't understand why this wont work.
EDIT: I am using RHEL5 and eclipse 3.6 if that makes a difference at all.
maybe you should wait on the thread filling the stream:
Thread thr = StreamGobbler.go(proc.getInputStream(), os);
// wait for the exit
try {
final int exitVal = proc.waitFor();
log.info("Command Exit Code: " + exitVal);
thr.join();//waits for the gobbler that processes the stdout of the process
} catch (InterruptedException e) {
log.error("Interrupted while waiting for command to execute", e);
}
Related
I have a batch and shell script that execute MYSQL command.
mysql -u user -p < path\etc\script\db\dosomething.sql
I have a java program that uses ProcessBuilder to execute the batch script.
I am aware that this command will prompt the user for the password , I am also aware that I can alternatively use the --password (which throws an unsafe warning) or a config file to set the login parameters.
I want to provide the password using the input prompt via ProcessBuilder but when I run the program it just hangs and I have no idea why.
When I use JVisualVM to view what is happening I notice that the OutputStream thread is not running and if it did then what is hanging the program ? Below is my implementation:-
Class that deals with the InputStream and ErrorStream :
public static class InStream extends Thread {
private final InputStream in;
private final PrintWriter pw;
public InStream(InputStream in, PrintWriter pw, String threadName) {
super(threadName);
this.in = in;
this.pw = pw;
}
#Override
public void run() {
try (BufferedReader br = new BufferedReader(new InputStreamReader(in));) {
String line;
while ((line = br.readLine()) != null) {
if (Thread.currentThread().isInterrupted()) {
Thread.currentThread().interrupt();
break;
}
pw.println(line);
pw.flush();
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
in.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
}
Class that deals with the OutputStream:
public static class OutStream extends Thread {
private final String message;
private final OutputStream out;
public OutStream(OutputStream out, String threadName, String message) {
super(threadName);
this.out = out;
this.message = message;
}
#Override
public void run() {
try (PrintWriter pw = new PrintWriter(out);) {
pw.println(message);
pw.flush();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
Here is the main program:
public static void main(String[] args) {
try {
String password = "Y0urp#ssw0rd";
ProcessBuilder builder = new ProcessBuilder("path\\etc\\script\\cli\\batchWithSQLCommand.bat");
Process process = builder.start();
StringWriter errors = new StringWriter();
StringWriter input = new StringWriter();
new OutStream(process.getOutputStream(), "output-stream-thread", password).start();
new InStream(process.getErrorStream(), new PrintWriter(errors, true), "error-stream-thread").start();
new InStream(process.getInputStream(), new PrintWriter(input, true), "input-stream-thread").start();
process.waitFor();
System.out.println("inputStream: " + input.toString());
System.out.println("Error Stream: " + errors.toString());
} catch (IOException | InterruptedException ex) {
//throw error here
} catch (Error | Exception ex) {
//throw error here
}
}
What could be the problem ?
I am new to creating batch files. I followed a tutorial and wrote a program to redirect the output of an echo programs's simple Java version into the file test.txt. I am supposed to get output as:
E:\classes\com\javaworld\jpitfalls\article2>java GoodWinRedirect test.txt (Tutorials's example)
OUTPUT>'Hello World'
ExitValue: 0
Instead, when i type
C:\Users\attsuap1\Desktop\JavaCallingBatchFile2\src>GoodwinRedirect.java test.txt in my command prompt, a WordPad page opens, showing the codes that is in the java class.
If i type
C:\Users\attsuap1\Desktop\JavaCallingBatchFile2\src>java GoodWinRedirect test.txt,
I get the error:
Error: Could not find or load main class GoodWinRedirect
These are the codes:
GoodWinRedirect.java
import java.util.*;
import java.io.*;
class StreamGobbler extends Thread {
InputStream is;
String type;
OutputStream os;
StreamGobbler(InputStream is, String type) {
this(is, type, null);
}
StreamGobbler(InputStream is, String type, OutputStream redirect) {
this.is = is;
this.type = type;
this.os = redirect;
}
public void run() {
try {
PrintWriter pw = null;
if (os != null)
pw = new PrintWriter(os);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
if (pw != null)
pw.println(line);
System.out.println(type + ">" + line);
}
if (pw != null)
pw.flush();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
public class GoodWinRedirect {
public static void main(String args[]) {
if (args.length < 1) {
System.out.println("USAGE java GoodWinRedirect <outputfile>");
System.exit(1);
}
try {
FileOutputStream fos = new FileOutputStream(args[0]);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("java jecho 'Hello World'");
// any error message?
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR");
// any output?
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT", fos);
// kick them off
errorGobbler.start();
outputGobbler.start();
// any error???
int exitVal = proc.waitFor();
System.out.println("ExitValue: " + exitVal);
fos.flush();
fos.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
How do i get the output as OUTPUT>'Hello World' ExitValue: 0 in the command prompt? Someone please help me. Thank you so much in advance.
The following batch script that works fine if I run it in a batch file (.bat). It gets all the files on the SFTP server and downloads to the local folder.
However, if I run this from the Java code, it gets only 4 files. Why is that it stops after it gets the 4 files?
Batch script:
winscp.com /log=C:\winscp\logs\winscp_detailed.log /xmllog=C:\winscp\logs\winscp.log /command ^
"open sftp://root:password#xx.xxx.xx.xx/ -privatekey=""C:\winscp\key.ppk"" -hostkey=""ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"" -passphrase=""password""" ^
"get /home/SFTP/* C:\LocalFolder1\" ^
"exit"
Java Code that executes the above command:
public HashMap runExternalProgram_Windows(String Command) {
String line;
InputStream stderr = null;
InputStream stdout = null;
HashMap _m = new HashMap();
try {
Process process = Runtime.getRuntime ().exec (Command);
Worker worker = new Worker(process);
worker.start();
try {
worker.join(30000);
if (worker.exit == null) {
throw new Exception();
}
} catch(Exception ex) {
_m.put("LOG_ERROR_EXTERNAL", "30 second time out...check connection");
ex.printStackTrace();
return _m;
} finally {
process.destroy();
}
stderr = process.getErrorStream ();
stdout = process.getInputStream ();
String _log_output = null;
// clean up if any output in stdout
BufferedReader brCleanUp = new BufferedReader (new InputStreamReader (stdout));
while ((line = brCleanUp.readLine ()) != null) {
if (_log_output==null) {
_log_output = line + "\n";
} else {
_log_output = _log_output + line + "\n";
}
}
brCleanUp.close();
_m.put("LOG_OUTPUT", _log_output);
String _log_error = null;
// clean up if any output in stderr
brCleanUp=new BufferedReader (new InputStreamReader (stderr));
while ((line = brCleanUp.readLine ()) != null) {
if (_log_error==null) {
_log_error = line + "\n";
} else {
_log_error = _log_error + line + "\n";
}
}
brCleanUp.close();
_m.put("LOG_ERROR_EXTERNAL", _log_error);
} catch (Exception e) {
//e.printStackTrace();
}
return _m;
}
private static class Worker extends Thread {
private final Process process;
private Integer exit;
private Worker(Process process) {
this.process = process;
}
public void run() {
try {
exit = new Integer(process.waitFor());
} catch (InterruptedException ignore) {
return;
}
}
}
Here is my sample code, I want to handle the command from standard input while running a new sub process. However, the exec method never returns if I read the system.in. The command in the exec() is very simple and has nothing to do with the stdin.
I'm wondering about is there any way to solve this? How can I start a new sub process while start another thread reading stdin?
public static void main(String[] args){
new Thread(new Runnable(){
public void run(){
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
try{
while((command = reader.readLine()) != null){
System.out.println("Command Received:" + command);
}
}catch(Exception ex){
ex.printStackTrace();
//failed to listening command
}
}
}).start();
Process process = null;
try {
process = Runtime.getRuntime().exec("java -cp C:/agenttest Test");
System.out.println("never returns");
process.waitFor();
} catch (IOException e) {
throw new RuntimeException( e );
} catch (InterruptedException e) {
throw new RuntimeException( e );
}
}
The Test class is very simple, here is the Test.java
public static void main(String[] args){
System.out.println("Standard out");
System.out.println("Standard out");
System.err.println("Standard err");
System.out.println("Standard out");
try{
Thread.sleep(10000);
}catch(InterruptedException ex){}
}
The problem could be that you're not handling the error stream and input stream and are overrunning the platform's buffers. Try handling that output as per the famous article, When Runtime.exec() won't.
For example:
import java.io.*;
public class TestMain {
private static final String JAVA_CMD = "java";
private static final String CP = "-cp";
// *** your CLASS_PATH and PROG Strings will of course be different ***
private static final String CLASS_PATH = "C:/Users/hovercraft/Documents/workspace/Yr 2012A/bin";
private static final String PROG = "yr12.m07.b.Test2";
private static final String[] CMD_ARRAY = { JAVA_CMD, CP, CLASS_PATH, PROG };
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String command = null;
try {
while ((command = reader.readLine()) != null) {
System.out.println("Command Received:" + command);
}
} catch (Exception ex) {
ex.printStackTrace();
// failed to listening command
}
}
}).start();
Process process = null;
try {
ProcessBuilder processBuilder = new ProcessBuilder(CMD_ARRAY);
process = processBuilder.start();
InputStream inputStream = process.getInputStream();
setUpStreamGobbler(inputStream, System.out);
InputStream errorStream = process.getErrorStream();
setUpStreamGobbler(errorStream, System.err);
System.out.println("never returns");
process.waitFor();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void setUpStreamGobbler(final InputStream is, final PrintStream ps) {
final InputStreamReader streamReader = new InputStreamReader(is);
new Thread(new Runnable() {
public void run() {
BufferedReader br = new BufferedReader(streamReader);
String line = null;
try {
while ((line = br.readLine()) != null) {
ps.println("process stream: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
You should keep reading the input stream, otherwise it will get blocked. It has nothing to do with JVM but the underyling operating system.
I wrote the code below. To run a bat file from Java app, I use a process.exec(). But the bat may hang sometime, so I need to set a timeout for this process. I start a new thread and new a process in the thread, I set a timeout in the thread, and kill the thread when it is timeout. But I found that the process couldn't be destroyed when timeout happens. So I am confused about how to kill the porcess?
The code:
StreamGobbler:
import java.util.*;
import java.io.*;
class StreamGobbler extends Thread
{
InputStream is;
String type;
StreamGobbler(InputStream is, String type)
{
this.is = is;
this.type = type;
}
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();
}
}
}
Main:
public class test
{
public static void main(String args[]) throws InterruptedException
{
Runnable r = new ShengThread();
Thread sheng = new Thread(r);
sheng.start();
sheng.join(1000);
if (sheng.isAlive()) {
sheng.interrupt();
}
if (sheng.isAlive()) {
System.out.println("It is dead.");
}
}
}
class ShengThread implements Runnable {
public void run() {
Process proc = null;
try
{
String osName = System.getProperty("os.name" );
String[] cmd = new String[3];
if( osName.equals( "Windows XP" ) )
{
cmd[0] = "cmd" ;
cmd[1] = "/C" ;
cmd[2] = "c:\\status.bat";
}
Runtime rt = Runtime.getRuntime();
System.out.println(osName+"Execing " + cmd[0] + " " + cmd[1]
+ " " + cmd[2]);
try {
proc = rt.exec(cmd);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// any error message?
StreamGobbler errorGobbler = new
StreamGobbler(proc.getErrorStream(), "ERROR");
// any output?
StreamGobbler outputGobbler = new
StreamGobbler(proc.getInputStream(), "OUTPUT");
// kick them off
errorGobbler.start();
outputGobbler.start();
// any error???
int exitVal = proc.waitFor();
System.out.println("ExitValue: " + exitVal);
} catch (InterruptedException t)
{
System.out.println("start\n");
proc.destroy();
t.printStackTrace();
}
}
}
The Process.destroy() method forcibly destroys an external process ... if this is possible. (In some situations you can't destroy processes, but that's only marginally relevant.)