Strange behaviour of readline in Java/Scala - java

I got a very strange problem. I am trying to read the result of a command I am executing. The code never reaches the println-Statement. It is just "hanging up" the program, if the end of the output is reached. No failure and no exception.
My project is a mix of Scala and Java. So it doesn't matter in which language the solution is. I tried in both. The encoding of my project is Cp1252.
Here is my code
var fileScript = Runtime.getRuntime().exec(PathOfScript)
var isr:InputStreamReader = new InputStreamReader(fileScript.getInputStream())
var in = new BufferedReader(isr)
var line:String = ""
try {
while ({line = in.readLine(); line!= null}) {
println("line: "+line)
}
println("OUTSIDE !!!");
in.close();
}

That's strange... my Java version works just fine:
InputStreamReader isr = new InputStreamReader(new FileInputStream("c:\\anyfile"));
BufferedReader in = new BufferedReader(isr);
String line = "";
try {
while ((line = in.readLine()) != null) {
System.out.println("line: "+line);
}
System.out.println("OUTSIDE !!!");
in.close();
} catch (Exception ex) {
ex.printStackTrace();
}
I think that the problem is in fileScript: if it gives a stream and doesn't close it, you'll never get a null in the while loop. Check that part. Try with a regular file (like I did in my example). If it works, the problem is surely in the fileScript object.

Related

Java code unable to use temporary file created (No output response from the process that executed the shell script)

I am writing a Java code that will create and write a shell command into temporary file which will be then used to run using process builder.
File file = null;
InputStream input = getClass().getResourceAsStream("/somecommand.sh");
try {
file = File.createTempFile("tempcmdline", ".sh");
} catch (IOException e1) {
e1.printStackTrace();
}
OutputStream out;
try {
out = new FileOutputStream(file);
BufferedReader reader=new BufferedReader(new InputStreamReader(input));
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(out));
String line;
while((line = reader.readLine()) != null) {
writer.write(line);
}
} catch (IOException e1) {
e1.printStackTrace();
}
Process p;
try {
List<String> cmdList = new ArrayList<String>();
cmdList.add("/usr/bin/bash");
cmdList.add("tempcmdline.sh");
ProcessBuilder pb = new ProcessBuilder(cmdList);
pb.redirectErrorStream(true);
p = pb.start();
IOUtils.copy(p.getInputStream(), System.out);
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
if((line = reader.readLine()) != null) {
System.out.println("some display" + line);
} else {
System.out.println("some other display");
}
I am getting error that tempcmdline.sh is not found. I tried adding /tmp/tempcmdline thinking default temporary directory used by createTempFile will be /tmp on UNIX.
Please share any working code where we can specify a directory and use it in process.
[EDIT] I tried getting absolutepath using file.getAbsolutePath() and pass full path name in process. However this is giving empty response (when I read the process output with InputStreamReader) while when I run the shell script manually on Unix it gives me a proper 1 line o/p message.
[EDIT] I figured out that temporary file getting created has \r which is causing the issue.
[UPDATE] Following is the updated code that worked for me:
File file = null;
InputStream input = getClass().getResourceAsStream("/someCommand.sh");
try {
file = File.createTempFile("tempcmdline", ".sh");
String tempShell = file.getAbsolutePath();
Files.copy(input, Paths.get(tempShell), REPLACE_EXISTING);
file.deleteOnExit(); //comment for testing to see how it is written
} catch (IOException e1) {
e1.printStackTrace();
}
Process p;
try {
String tempShellFile = file.getAbsolutePath();
List<String> cmdList = new ArrayList<String>();
cmdList.add("sh");
cmdList.add(tempShellFile);
cmdList.add(applicationName);
cmdList.add(serviceAccount);
ProcessBuilder pb = new ProcessBuilder(cmdList);
//pb.redirectErrorStream(true);
p = pb.start();
//IOUtils.copy(p.getInputStream(), System.out); //uncomment for testing
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
if((line = reader.readLine()) != null) {
System.out.println("some message");
} else {
System.out.println("some other message");
}
}catch (IOException e) {
e.printStackTrace();
}catch (InterruptedException e) {
e.printStackTrace();
}
Error details and learnings to share:
1) Initial issue was that response from process was leading to no InputStream. To debug I used IOUtils.copy(p.getInputStream(), System.out);
Then, actual error showed up from process stating no such file found (tempcmdline.sh)
2) Upon understanding that a temporary file name will be different, I got the absolute path and passed it to the process.
Next error was no response as though shell script was empty. Loop above in initial code did not handle newline and was incorrect. New code added has the fix.
Next error was invalid characters "\r" which was due to shell script file created on Windows. I simply cleaned it on Eclipse editor and it was fine.
3) After debugging I removed IOUtils.copy step as I wanted the output to be read through Inputstream.
Hope it helps someone..
It appears that you are attempting to write to a temp file, named something like "/tmp/tempcmdline234765876.sh", and then you are attempting to run "tempcmdline.sh".
Add a System.out.println(file); to see what the actual temp filename is.

wkhtmltopdf called from java getting hanged

We are the using the following code to generate PDFs using wkhtmltopdf
public class SystemUtils{
public String executeCommand(String... command) {
Process process = null;
try {
// Using redirectErrorStream as true. Otherwise we have to read both process.getInputStream() and
// process.getErrorStream() in order to not exhaust the stream buffer.
process = new ProcessBuilder(command).redirectErrorStream(true).start();
process.waitFor();
StringBuilder outputBuilder = new StringBuilder();
try(BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = stdError.readLine()) != null) {
outputBuilder.append(line).append(StringConstants.CARRIAGE_RETURN);
}
}
return outputBuilder.toString();
} catch (IOException | InterruptedException e) {
String exceptionMsg = "Error while executing command '"+command+"' : ";
LOGGER.error(exceptionMsg, e);
throw new AppException(exceptionMsg, e);
} finally {
if(process != null){
process.destroy();
}
}
}
public static void main(String[] args){
SystemUtils systemUtils = new SystemUtils();
String[] array = {"wkhtmltopdf", "/home/pgullapalli/Desktop/testsimilar1.html", "/home/pgullapalli/Desktop/test.pdf"};
systemUtils.executeCommand(array);
}
}
This works absolutely fine for smaller size files. But when we try to process a larger file, it is indefinitely waiting without any response. I am not sure what is going wrong? Can someone please suggest?
I moved process.waitFor() before the return statement and it started working. This probably could be happening as the output buffer has filled and we are not reading from it. After moving the process.waitFor after the stream reading, things are working fine.

How to check if two files are having same content using Beyond Compare java api?

I have two files to be given as an input and I am using Beyond Compare tool Java API to check whether the contents in both the files are same or not.
I want to do this without opening the Beyond Compare window. Below is the code which I am using currently.
ProcessBuilder processBuilder = new ProcessBuilder("C:\\Program Files\\Beyond Compare 4\\BCompare.exe",
"file1path", "file2path","/qc=bin", "\silent");
Process ps;
try {
ps = processBuilder.start();
OutputStream os = ps.getOutputStream();
os.close();
InputStream inputStream = ps.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) {
}
ps.waitFor();
System.out.println("Exit value :" + ps.exitValue());
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
As mentioned here enter link description here, using /silent will not open the window. Despite using /silent, I can still see the window pop up of Beyond Compare tool. Please suggest some work around to achieve the same
I met my requirement by slightly changing the arguments passed to the Process Builder. Below is the change I made.
ProcessBuilder processBuilder = new ProcessBuilder("C:\\Program Files\\Beyond Compare 4\\BCompare.exe",
"file1path", "file2path","/fv=Text Compare", "/qc=binary");
This worked for me.

sshj: how to read InputStream from long-running command while command is executing

Currently I am executing command over ssh using:
val sshCmd = session.exec(command)
println(IOUtils.readFully(sshCmd.inputStream).toString())
sshCmd.join()
However, to see the output I need to wait until the command is finished.
How can I get "live" response?
I guess I can read the input stream until end of the line occurs and then print the line; however, is there already some method in the library that can help me with this?
It blocks and waits for the whole thing because that's what IOUtils.readFully is meant to do, it reads fully.
Instead, to read line-by-line, you can do something as simple as:
try (BufferedReader reader = new BufferedReader(new InputStreamReader(sshCmd.inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println(e);
}

Java: How do i check if another class file is running?

Well, i'm working a project to test my knowledge of java programming.
My project is a game and i'm making some kind of launcher for it that closes when the project has fully booted. I searched on the web to see how i check if a java program is running or not. I found a way to see if a program is running (here is the link to it or see code below). I tested it but it didn't work so i searched for the answer to check if a process/program is running under a "bigger" program (exemple: multiple windows in firefox). I didn't find it so i hope that you know the answer.
Here is the way to check if a program is running that i found (And here is the link again):
String line;
String pidInfo ="";
Process p =Runtime.getRuntime().exec(System.getenv("windir") +"\\system32\\"+"tasklist.exe");
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
pidInfo+=line;
}
input.close();
if(pidInfo.contains("file.class"))
{
// do what you want
}
Instead of checking whether the game process is running (Which isn't so possible with the pid, since that's a number), you can check the contents of a file:
File f = new File("path_to_file.txt");
BufferedReader br;
String text = "";
try {
br= new BufferedReader(new FileReader(f));
String line;
while((line = br.readLine())!=null){
text+=line;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(text.equals("started")){
// we have to make sure it can work next time so we clear the file's contents
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
bw.write("");
bw.flush();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
//close launcher
}
And then the only thing left to do is have the game write to that file the text "started" after it has started.

Categories