Reading the input stream of one JVM from another JVM [closed] - java

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Goal: to initialise a JVM(2) from a separate JVM(1) using ProcessBuilder, capturing the resulting output from JVM(2) and displaying the result within a JTextArea in JVM(1).
Situation: able to launch JVM(2) from within JVM(1) and capture the resulting output from JVM(2) to a JTextArea within the JVM(1).
Problem: the JVM(2) will not respond to input until JVM(1) is terminated.
Thread inside VJM(1) that starts JVM(2):
Runnable runnable = () -> {
try {
JVMBooter.startSecondJVM();
} catch (Exception ex) {
Logger.getLogger(MyMenu.class.getName()).log(Level.SEVERE, null, ex);
}
};
Thread t = new Thread(runnable);
t.start();
JVMBooter source code:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
public class JVMBooter {
public static void startSecondJVM() throws Exception {
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "startscript.bat");
File dir = new File("D:/Server");
pb.directory(dir);
Process p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
( (line = reader.readLine()) != null && ! line.trim().equals("--EOF--")) {
OutputFrame.textArea.append(line + "\n");
}
}
}
The JVM(2) is started within the startscript.bat file with:
java -jar server.jar

Depending on the situation it may be necessary to read the error stream instead of the input stream, e.G. if your second java call is -version or the program you call only writes to stderr instead of stdout getting the Error Stream is the correct approach.
I wrote this MCVE:
import java.io.*;
public class Starter {
public static void main(String[] args) throws IOException {
ProcessBuilder pb = new ProcessBuilder("./dosomething.sh");
File dir = new File(new File(File.listRoots()[0], "tmp"), "2jvm");
pb.directory(dir);
Process p = pb.start();
BufferedReader read = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line;
while ( (line = read.readLine() ) != null) {
System.out.println("line: " + line);
}
}
}
and in 'dosomething.sh' this:
echo before
java -version
echo after
when I use p.getInputStream I would get the 'before' and 'after'. When I use p.getErrorStream I get the Java Version Information.
That might be true for you too. I suggest you add echo lines in your batch file to see if they get printed out.
I also wrote a simple hello world and when I called that from dosomething.sh it got printed to the input stream as expected. It is a weird quirk of -version to write to stderr.
For completeness here is the Hello World I used (it has waits to simulate a longrunning server process):
public class Caller {
public static void main(String[] args) {
synchronized(Caller.class) {
for(int ii = 0; ii < 10; ii++) {
try {
Caller.class.wait(1000);
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("Hello world! " + ii);
}
}
}
}

Related

Restrict Powershell from printing input commands to output stream

I am using Java ProcessStream to write input commands to powershell on my local machine. Now, the problem is that along with the output, I am seeing input commands as well. How can I restrict input command from being shown on the output.
Below is the code to reproduce the same:
public class Example {
public static boolean isAlive(Process o) {
try {
p.exitValue();
return false;
} catch (Exception e) {return true;}
}
public stati void main(String[] args) throws IOException {
ProcessBuilder builder = new ProcessBuilder("powershell");
builder.redirectErrorStream(true);
Process process = builder.start();
InputStream out = process.getInputStream();
OutputStream in = process.getOutputStream();
String bufferString = "echo hello \n";
byte[] buffer = bufferString.getBytes();
int n = buffer.length;
in.write(buffer, 0, n);
in.flush();
while(isAlive(process)) {
int no = out.available();
if (no >0) {
int m = out.read(buffer, 0, Math.min(no, buffer.length));
System.out.println(new String(buffer, 0, m));
}
}
}
}
OUTPUT:
PS C://> echo hello
hello
I need only "hello" in output.
The following works for me (but the java program never terminates and I have to kill it).
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
public class Example {
public static boolean isAlive(Process p) {
try {
p.exitValue();
return false;
}
catch (Exception e) {
return true;
}
}
public static void main(String[] args) throws IOException {
ProcessBuilder builder = new ProcessBuilder("powershell", "-NoLogo");
builder.redirectErrorStream(true);
Process process = builder.start();
InputStream is = process.getInputStream();
try (InputStreamReader isr = new InputStreamReader(is);
BufferedReader out = new BufferedReader(isr)) {
OutputStream in = process.getOutputStream();
String bufferString = "echo hello" + System.lineSeparator();
byte[] buffer = bufferString.getBytes();
in.write(buffer);
in.flush();
while (isAlive(process)) {
String line = out.readLine();
if (!line.startsWith("PS")) {
System.out.println(line);
}
}
}
}
}
The output produced by the above code is simply:
hello
#talex mentioned the following in his comment to your question:
it is impossible to get rid of PS C://> part
This is not true since you can customize the PowerShell prompt but you wrote that you don't want to see the echo hello in the output and that is not possible and therefore, as #talex mentioned:
you have to filter your input stream yourself
Not displaying echo hello means not displaying the entered command. Imagine that you open a PowerShell window and don't see the command you entered but after you hit ENTER you want to see the output. So I don't think that there is a way to not display echo hello and therefore, in the above code, I don't print lines that start with the PowerShell prompt.
You can find details about launching PowerShell in about_PowerShell_exe

Why can't I re-execute a Java program from within an Exception block? [duplicate]

This question already has answers here:
Capture SIGINT in Java
(3 answers)
Closed 7 years ago.
I'm trying to run the following Java code which is supposed to automatically restart itself when I kill it via CTRL + C on windows command-line :
import java.net.*;
import java.io.*;
public class LineRunner extends Thread {
public static void main(String[] args) throws InterruptedException, IOException{
try {
for (int i = 0; i<10000000; i++) {
Thread.sleep(200);
System.out.print("hithe");
}
}
catch( InterruptedException ioex) {
String[] command = {"C://Program Files//Java//jdk1.7.0_02//bin//java.exe", "LineRunner"};
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
Process exec = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(exec.getInputStream()));
String text = null;
while ((text = br.readLine()) != null) {
System.out.println(text);
}
System.out.println("Process exited with " + exec.waitFor());
}
}
}
But when I kill from command line (via CTRL + C ) , it does not restart the program as I wish.
Any tips appreciated, thanks
You need use addShutdownhook to listen the program exit and you can restart your program in there.
Ctrl-C will exit the JVM as has already been discussed in comments.

executing cat command from java program does not work as expected

I am trying to use the cat command from within a java program to merge two files into one. The line of code which contains the cat command takes two files file1 and file2 and writes to a third file called combinedfile. However, what I observe is the instead of creating this file (combinedfile) and writing to it, my program merely displays the output on the terminal.
How can I make sure that indeed the two files are copied to a third file.
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ExecuteShellCommand
{
public static void main(String[] args)
{
ExecuteShellCommand obj = new ExecuteShellCommand();
String command = "cat file1 file2 > combinedfile";
String output = obj.executeCommand(command);
System.out.println(output);
}
private String executeCommand(String command)
{
StringBuffer output = new StringBuffer();
Process p;
try
{
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null)
{
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
EDIT:
I tried out with the ProcessBuilder as suggested, but I get this error.
Code
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.*;
import java.util.*;
public class ExecuteShellCommand
{
public static void main(String[] args)
{
try
{
ProcessBuilder builder = new ProcessBuilder("cat", "/home/PepperBoy/Desktop/file1.txt","/home/PepperBoy/Desktop/file2.txt");
File combinedFile = new File("/home/PepperBoy/Desktop/file3.txt");
builder.redirectOutput(combinedFile);
builder.redirectError(combinedFile);
Process p = builder.start();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
Error
ExecuteShellCommand.java:14: cannot find symbol
symbol : method redirectOutput(java.io.File)
location: class java.lang.ProcessBuilder
builder.redirectOutput(combinedFile);
I found a related question. To summarize the useful things from a couple answers found there, file redirection requires a shell, but exec doesn't have a shell context. Luckily, you can execute processes with redirection using ProcessBuilder. For your case, that would look something like:
public static void main(String[] args)
{
try{
ProcessBuilder builder = new ProcessBuilder("cat", "file1","file2");
File combinedFile = new File("combinedFile");
builder.redirectOutput(combinedFile);
builder.redirectError(combinedFile);
Process p = builder.start();
} catch(IOException e){
//handle exception...
}
}
Note: You may receive an error when calling redirectError or redirectOutput stating that the symbol cannot be found. This will occur if you are compiling against a version of Java before 1.7, since 1.7 is when these methods were introduced. If it is possible to upgrade your Java, doing so will eliminate this error.
If it is not possible to upgrade Java, the following code will work:
public static void main(String[] args)
{
try{
ProcessBuilder builder = new ProcessBuilder("cat", "file1","file2");
File combinedFile = new File("combinedFile");
Process p = builder.start();
InputStream isFromCat = p.getInputStream();
OutputStream osCombinedFile = new FileOutputStream(combinedFile);
byte[] buffer = new byte[1024];
int read = 0;
while((read = isFromCat.read(buffer)) != -1) {
osCombinedFile.write(buffer, 0, read);
}
} catch(IOException e){
//handle exception...
}
}
It is also probably worthwhile to note that making a system call to cat is not the optimal way to combine files from Java. I have been assuming this is a toy case to represent a more complex use case for you. If all you really want to do is combine two files, you should write your code to avoid system calls and just append the files by reading both in as input streams and then writing them out to the result file. If you're having trouble figuring that out, those details definitely belong in another question.

How to get total number of lines in a file in linux using java

I am trying to run wc -l filename command using Runtime.getRuntime().exec(command) and get the total number of lines. But it is not working.
Here is my code :
private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
System.out.println(command);
p = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line.split("\\s+")[0] + "\n");
}
int exc = p.waitFor();
System.out.println(exc);
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
exc (the exit value) is coming out zero. When I am printing the command which I am passing, it gives the right command. I have also tried to copy that command and run it in Linux. It's working, but not through program.
Command which I am passing to command variable in the functionexecuteCommand is:
wc -l < log1
Total number of lines it contains around 4597110. Also I dont want the size of file in bytes, I have to get the total number of lines only.
An easier alternative for getting the lines (with Java 8).
long lines = Files.lines(Paths.get("foo.txt")).count();
Kayaman has a much better answer if you're on Java 8 or better. If, however, you're stuck on an earlier iteration, see below.
You see this bit of code that you use for evaluating the output of wc:
while ((line = reader.readLine())!= null) {
output.append(line.split("\\s+")[0] + "\n");
}
That's remarkably similar to the code that could just read the file directly and count the number of lines.
So I'm not entirely certain why you think there's a need to call an external program to do this task, especially as it degrades the portabilty of your code.
Just open the file and read the lines, adding one to a counter for each line. And there you have it, the line count.
See, for example, the following file:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
public class Test
{
static private int getLineCount(String fspec) {
String line;
int count = 0;
try {
BufferedReader reader = new BufferedReader(
new FileReader(new File(fspec)));
while ((line = reader.readLine())!= null)
count++;
} catch (Exception e) {
count = -1;
}
return count;
}
public static void main(String[] args) {
System.out.println (getLineCount("/tmp/tempfile"));
}
}
Running this gives 140 as does the output from wc -l:
pax> wc -l /tmp/tempfile
140 /tmp/tempfile
Looks like you don't pass correct path to the file, try this when you run method:
URL fileName = ClassLoader.getSystemClassLoader().getResource("filename");
System.out.println(executeCommand("wc -l " + fileName.getPath()));
Try using Process in the following way:
ProcessBuilder pb = new ProcessBuilder("wc", "-l");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));){
Process process = pb.start();
while (reader.readLine() != null){
// you need to figure out in which line the
// relevant output is and parse that to int
// just look at some sample outputs of wc -l
}
int err = process.waitFor();
if(err!=0) {
// your code for processing the number of lines goes here
// the command finished without error
}
else {
// your code here in case the command had an error
}
} catch (Exception e){
// catch an Exception like IOException or InterruptedException here
}
Basically the Reader will read the output from the command that would go to the terminal when executing the command there.
You can use apache common io FileUtils.readLines(File file)
FileUtils.readLines(new File("filename.txt")).size()

Is it possible to run cmd through a java program [duplicate]

This question already has answers here:
Start CMD by using ProcessBuilder
(3 answers)
Closed 9 years ago.
I would like to know if its possible to run cmd through Java. Not just one command at a time but a continuous stream of user input commands that relays the info received. Is this possible or should I just stop trying now?
I'm not sure why I'm attaching this; it's not very relevant, but this is what I was trying to accomplish this with. However, it resets the cmd after every command. (Yes, I realize this is bad coding, but I'm just attempting something my boss asked about.)
import java.io.*;
import java.util.Scanner;
public class Cmd {
public static void main(String[] args) throws IOException {
String line;
while (true) {
Scanner scanner = new Scanner(System.in);
String comm = scanner.nextLine();
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", comm);
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
while (true) {
line = r.readLine();
if(line==null){break;}
System.out.println(line);
}
}
}
}
Basically, cmd but behind a Java GUI with user input commands is my end game. If anyone could tell me if this is possible and if so point me in the right direction I would be grateful.
Yes, it is possible.
At the end of my answer is an example program. It is far from perfect and is missing some implementation details. For example proper exception handling and also detect when the cmd has exited... But it may be used as a starting point.
In essence the solution to your question is to start cmd.exe as a new Process. Then read commands in java from standard input stream (System.in) and pipe it to the cmd.exe-process. To provide feedback to the user you must read the standard output from cmd.exe-process and print it to the standard output of your java process (System.out). Also read standard error from cmd.exe-process and print it to standard error of your java process (System.err).
Close all resources when you are done. I indicated this in the example, but this is not production ready. Any exception would prevent the example program from cleaning up.
Another implementation detail: The example program uses a second thread to read output from cmd.exe-process. Otherwise you will only get output when the user hits enter.
Finally, here is the code:
package com.example;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class JavaCmd {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
ProcessBuilder procBuilder = new ProcessBuilder("cmd.exe");
Process proc = procBuilder.start();
PrintWriter outToProc = new PrintWriter(proc.getOutputStream());
final BufferedReader inFromProc = new BufferedReader(new InputStreamReader(proc.getInputStream()));
final BufferedReader errorFromProc = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Thread outputThread = new Thread(new Runnable(){
#Override
public void run() {
while(true) {
try {
while(inFromProc.ready()) {
String line = inFromProc.readLine();
System.out.println(line);
}
while(errorFromProc.ready()) {
String line = errorFromProc.readLine();
System.err.println(line);
}
} catch (IOException e) {
throw new RuntimeException("Error in output thread", e);
}
try {
Thread.sleep(100);
} catch(InterruptedException e) {
System.out.println("Output Thread interrupted -> Thread will terminate");
break;
}
}
}
});
outputThread.start();
System.out.println("\n\nProxy shell is ready. Enter 'quit' to leave program.\n\n");
System.out.flush();
String line = null;
while((line = reader.readLine()) != null) {
if(line.equalsIgnoreCase("quit")) {
System.out.println("Good Bye");
break;
}
outToProc.println(line);
outToProc.flush();
}
reader.close();
outputThread.interrupt();
proc.destroy();
}
}

Categories