Using an self-edited StreamGobbler to run a php script,
I am trying to input commands into the script while it is running...
StreamGobbler.java
private class StreamGobbler extends Thread {
InputStream is;
OutputStream os;
String line;
PMRunnerPro main;
public StreamGobbler(InputStream is, OutputStream os, PMRunnerPro main) {
this.is = is;
this.os = os;
this.main = main;
}
#Override
public void run() {
try {
BufferedReader reader = new BufferedReader (new InputStreamReader(is));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
if (main.sSendNeeded) {
System.out.println("Sent");
writer.write(main.sCommand + "\n");
main.sSendNeeded = false;
main.sCommand = "";
}
main.outputBox.setText(main.outputBox.getText() + (line + "\n"));
line = reader.readLine();
}
writer.flush();
} catch(IOException ex) {
main.sRunning = false;
}
System.out.println("Over");
main.sRunning = false;
}
}
The command is sent to the script only when there is an output from the script.
I want the Thread to continuously check if there is any command to send to the script and then do so if there is any.
If I understood your intentions correctly...
Since you using blocking I/O, you need two threads for what you want:
1st thread will read script output, as you do now. Once output available, it will be shown in textarea;
2nd thread will read input from queue and forward it to script.
Here's code draft (notice that you may want to add synchronization between input and output workers, so input worker won't be able to send new command to script until previous command produces output from script, but that's up to you):
class InputWorker implements Runnable {
#Override
public void run() {
try {
BufferedReader reader = new BufferedReader (new InputStreamReader(is));
String line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
// show script output
}
} catch(IOException ex) {
//
}
}
}
class OutputWorker implements Runnable {
final BlockingQueue<String> commandQueue = new ArrayBlockingQueue<String>();
public void sendCommand(String command) {
commandQueue.add(command);
}
#Override
public void run() {
try {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
while (true) {
String command = commandQueue.take();
if ("EXIT".equals(command)) { return; }
writer.write(command);
writer.flush();
}
} catch(IOException ex) {
//
} catch (InterruptedException e) {
//
}
}
}
Related
I'm creating a NetUtils class which extends thread to handle socket communications in a GUI without blocking the main thread. My code looks like the following (assume all import are accounted for):
Main method
public static void main(String[] args) {
EventQueue.invokeLater( () -> {
new Window().setVisible(true);
});
}
Window class
public class Window { // normally would extend JFrame bc this is a gui
// ...
NetUtils comms;
public Window() {
// ...
comms = new NetUtils("192.168.1.1", 288); // this ip/port info works fine
comms.start();
// ...
}
// other methods....
}
NetUtils class
public class NetUtils extends Thread {
private String ip;
private int port;
public NetUtils(String ip, int port) {
this.ip = ip;
this.port = port;
}
#Override
public void run() {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(ip, port), 10000); // timeout 10s
System.out.println("Socket started: " + socket); // correctly prints
while (true) { // during the life of the thread
String line = readLine(socket); // throws SocketException here (socket closed error)
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String readLine(Socket socket) {
// uses inputstream to read bytes and such
String line;
boolean isDone = false;
while (!isDone) {
try (InputStreamReader isr = new InputStreamReader(socket.getInputStream))) {
if (isr.ready()) {
line += (char) isr.read();
}
if (!isr.ready() && line != "") {
isDone = true;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return line;
}
}
What am I doing that would cause the socket to close? I ran the NetUtils code directly in the main method (I didnt separate out the readLine method) and it ran as I expected it to which lead me to believe the problem has to do with the socket being in a thread. Thanks for the help.
Clearly 'this part works' is closing the socket or its input or output stream.
NB You aren't checking for end of stream in the code you posted. I don't see the need for the readLine() method. Just replace your loop with this:
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
reader.close();
[exception handling omitted.]
I was trying to get the logcat content into a JTextPane. I used following code hoping it will return the content as String but it freeze and also, doesn't produce an error.
Process exec = null;
try {
exec = Runtime.getRuntime().exec("adb logcat -d");
InputStream errorStream = exec.getErrorStream();
BufferedReader ebr = new BufferedReader(new InputStreamReader(errorStream));
String errorLine;
while ((errorLine = ebr.readLine()) != null) {
System.out.println("[ERROR] :- " + errorLine);
}
if (exec.waitFor() == 0) {
InputStream infoStream = exec.getInputStream();
InputStreamReader isr = new InputStreamReader(infoStream);
BufferedReader ibr = new BufferedReader(isr);
String infoLine;
while ((infoLine = ibr.readLine()) != null) {
System.out.println("[INFO] :- " + infoLine);
}
}
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
} finally {
if (exec != null) {
exec.destroy();
}
}
I referred to some tutorials but, they were not filling my problem. Is this wrong? Are there any other methods to get the logcat content as a String programmatically? Sorry if this is a dumb question.
The issue you're seeing is that you're trying to process command streams and wait for the executing process, all in the same thread. It's blocking because the process reading the streams is waiting on the process and you're losing the stream input.
What you'll want to do is implement the function that reads/processes the command output (input stream) in another thread and kick off that thread when you start the process.
Second, you'll probably want to use ProcessBuilder rather than Runtime.exec.
Something like this can be adapted to do what you want:
public class Test {
public static void main(String[] args) throws Exception {
String startDir = System.getProperty("user.dir"); // start in current dir (change if needed)
ProcessBuilder pb = new ProcessBuilder("adb","logcat","-d");
pb.directory(new File(startDir)); // start directory
pb.redirectErrorStream(true); // redirect the error stream to stdout
Process p = pb.start(); // start the process
// start a new thread to handle the stream input
new Thread(new ProcessTestRunnable(p)).start();
p.waitFor(); // wait if needed
}
// mimics stream gobbler, but allows user to process the result
static class ProcessTestRunnable implements Runnable {
Process p;
BufferedReader br;
ProcessTestRunnable(Process p) {
this.p = p;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(p.getInputStream());
br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null)
{
// do something with the output here...
}
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
I need to execute a command in my java program but after executing the command , it required another parameter ( a password in my case ). how can I manage the output process of Runtime.getRuntime().exec() to accept parameter for further execution ?
I tried new BufferedWriter(new OutputStreamWriter(signingProcess.getOutputStream())).write("123456"); but it did not work.
Does your program not feature a --password option ? Normally all command line based programs do, mainly for scripts.
Runtime.getRuntime().exec(new String[]{"your-program", "--password="+pwd, "some-more-options"});
Or the more complicated way and much more error-prone:
try {
final Process process = Runtime.getRuntime().exec(
new String[] { "your-program", "some-more-parameters" });
if (process != null) {
new Thread(new Runnable() {
#Override
public void run() {
try {
DataInputStream in = new DataInputStream(
process.getInputStream());
BufferedReader br = new BufferedReader(
new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
// handle input here ... ->
// if(line.equals("Enter Password:")) { ... }
}
in.close();
} catch (Exception e) {
// handle exception here ...
}
}
}).start();
}
process.waitFor();
if (process.exitValue() == 0) {
// process exited ...
} else {
// process failed ...
}
} catch (Exception ex) {
// handle exception
}
This sample opens a new thread (keep in mind concurrency and synchronisation) that's going to read the output of your process. Similar you can feed your process with input as long as it has not terminated:
if (process != null) {
new Thread(new Runnable() {
#Override
public void run() {
try {
DataOutputStream out = new DataOutputStream(
process.getOutputStream());
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(out));
bw.write("feed your process with data ...");
bw.write("feed your process with data ...");
out.close();
} catch (Exception e) {
// handle exception here ...
}
}
}).start();
}
Hope this helps.
Runtime r=Runtime.getRuntime();
process p=r.exec("your string");
try this way
You should give in parameter your windows command if you work on windows
visit this link for more details : http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html
I have an IRC bot which hosts game servers given a few arguments. The problem is, once it hosts a server, it stops listening to IRC (meaning realistically, only one server can be hosted at a time). This is not what I want.
I assumed threading would be the answer to my problem, but I can't seem to get it to work. It appears that it doesn't actually start in another thread?
Here is my main class which starts and runs the method via threading:
// Everything is okay, run the server.
Runnable r = new Server(this, channel);
Thread thread = new Thread(r);
thread.start();
And here is the Server class which (presumably) controls the threading:
public class Server extends PircBot implements Runnable {
public void run() {
}
public Server (bot BotRun, String channel) {
String names[] = org.bestever.bebot.bot.hostbuilder.split(" ");
ProcessBuilder pb = new ProcessBuilder(names);
pb.redirectErrorStream(true);
try {
Process proc = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String strLine = null;
while((strLine = br.readLine()) != null) {
// Returns UDP Initialized if the server was successfully started
if (strLine.equalsIgnoreCase("UDP Initialized.")) {
BotRun.sendMessage(channel, "Server started successfully.");
}
// Returns Bad Hex Number if there is a problem with the WAD file
else if (strLine.startsWith("Bad hex number")) {
BotRun.sendMessage(channel, "Error starting server: "+strLine);
}
System.out.println(strLine);
}
Thread.currentThread().interrupt();
} catch (IOException e) {
e.printStackTrace();
}
}
Have I not actually started it in a thread? Thanks for any help!
I am afraid, not.
Server class should be more like:
public class Server extends PircBot implements Runnable {
private bot BotRun;
private String channel;
public void run() {
String names[] = org.bestever.bebot.bot.hostbuilder.split(" ");
ProcessBuilder pb = new ProcessBuilder(names);
pb.redirectErrorStream(true);
try {
Process proc = pb.start();
Reader reader = new InputStreamReader(proc.getInputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String strLine = null;
while((strLine = br.readLine()) != null) {
// Returns UDP Initialized if the server was successfully started
if (strLine.equalsIgnoreCase("UDP Initialized.")) {
BotRun.sendMessage(channel, "Server started successfully.");
}
// Returns Bad Hex Number if there is a problem with the WAD file
else if (strLine.startsWith("Bad hex number")) {
BotRun.sendMessage(channel, "Error starting server: "+strLine);
}
System.out.println(strLine);
}
reader.close();
Thread.currentThread().interrupt();
} catch (IOException e) {
e.printStackTrace();
}
}
public Server (bot BotRun, String channel) {
this.BotRun = BotRun;
this.channel = channel;
}
}
Your run() method is empty; it starts, does nothing, and ends.
I'm running a Java program from another Java application using Runtime.getRuntime().exec like this
Process p1 = Runtime.getRuntime().exec("javac test.java");
Process p2 = Runtime.getRuntime().exec("java test");
The content of the test.java
import java.io.*;
class test
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
System.out.println(s);
}
}
I want to handle Input, Output and Error stream of the process p2.
I did capture of the output of the test.java, however, I do not know how to handle output and error.
Here is my code:
try {
String s = "";
InputStream istr = p2.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(istr));
BufferedReader bre = new BufferedReader
(new InputStreamReader(p2.getErrorStream()));
while ((s = br.readLine()) != null) {
System.out.println(s);
}
br.close();
while ((s = bre.readLine()) != null) {
System.out.println(s);
}
bre.close();
p2.waitFor();
} catch (IOException ex) {
ex.printStackTrace();
} catch (Exception err) {
err.printStackTrace();
}
The code above works fine for capturing the output of the test.java. But it does not display error of the test.java.
Could you please give me a sample code for fixing this problem and handling output stream or share idea? Thanks in advance
The solution I've always used is to create a separate thread to read one of the streams
So, in your case it should be something like
String s = "";
InputStream istr = p2.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(istr));
BufferedReader bre = new BufferedReader
(new InputStreamReader(p2.getErrorStream()));
new Thread(new Runnable() {
#Override
public void run() {
while ((s = br.readLine()) != null) {
System.out.println(s);
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
while ((s = bre.readLine()) != null) {
System.out.println(s);
}
}
}).start();
// when you are finished close streams