Java Process Builder - java

I have a project where program has to open notepad file and after entering text and saving that notepad file program should display number of words in that file and it should delete the entered content in the file.
iam getting this error Error not derjava.lang.NullPointerException after running the program.
though after entering some text in Mytext.txt and saving it?
my question is why BufferedReader is reading empty file even though iam saving the file with some content.
Appreciate the help..
public class Notepad_Example {
public static void main(String[] jfb) {
try {
ProcessBuilder proc = new ProcessBuilder("notepad.exe", "C:\\Java Projects\\Reverse String\\src\\Mytext.txt");
proc.start();
BufferedReader br;
String s;
br = new BufferedReader(new FileReader("C:\\Java Projects\\Reverse String\\src\\Mytext.txt"));
s = br.readLine();
char c[] = new char[s.length()];
int j = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) != ' ') {
c[i] = s.charAt(i);
} else {
j++;
}
}
System.out.println("number of words are " + (j + 1));
br.close();
} catch (Exception hj) {
System.out.println("Error not der" + hj);
}
try {
FileWriter fw = new FileWriter("C:\\Java Projects\\Reverse String\\src\\Mytext.txt");
fw.close();
} catch (Exception hj) {
System.out.println("Error not der" + hj);
}
}
}

The issue you are having is here:
ProcessBuilder proc=new ProcessBuilder("notepad.exe","C:\\Java Projects\\Reverse String\\src\\Mytext.txt");
proc.start();
proc.start() is returning the freshly started process. You'll have to give the user the chance to edit and save the file and close the editor before you can read from that file. That is you have to wait for that process to finish before you can start using the results (the saved file) of that process.
So do instead something like this:
Process process = proc.start();
int result = process.waitFor();
if (result == 0) {
// Do your rest here
} else {
// give error message as the process did not finish without error.
}
Some further remarks:
The rest of your code also appears to have some issues.
You are only reading one line of that file. What if the user is using new lines?
The exception handling is not very good, at the very least print the stack trace of the exception which will give you further hints of where an exception was occuring
If you are using Java 7, read on try with resources; if you are using Java 6, add finally blocks to make sure your resources (the streams) are getting closed.

When you run proc.start(); it is not going to block and waitfor the process to end, it will continue running.
You will need to call the proc.waitFor() method, to block until it has finished.

NOTE
we have had some weird behaviour when using the process builder...
we used to start the process with a
new ProcessBuilder("notepad.exe", "C:\\Java Projects\\Reverse String\\src\\Mytext.txt");
but that started to fail wen we upgraded to Win7 and Java7 - we we not sure where this problem really originated, but we changed out Code like this:
String[] cmd = new String[]{"notepad.exe", "C:\\Java Projects\\Reverse String\\src\\Mytext.txt"};
new ProcessBuilder(cmd);
and since then it worked correct!

Related

executing C from Java strange errors

I am using Java as a front end for a chess AI i am writing. The Java handles all the graphics, and then executes some C using a few command line arguments. Sometimes the C will never finish, and not get back to the Java. I have found cases in which this happens, and tested them with just the .exe and no java. When i take out the java, these cases work everytime. I am not sure where to go from here. Here is some code that i think is relavant, and the whole project as at https://github.com/AndyGrant/JChess
try{
Process engine = Runtime.getRuntime().exec(buildCommandLineExecuteString(lastMove));
engine.waitFor();
int AImoveIndex = engine.exitValue();
String line;
BufferedReader input = new BufferedReader(new InputStreamReader(engine.getInputStream()));
while ((line = input.readLine()) != null)
System.out.println(line);
input.close();
if (AImoveIndex == -1){
activeGame = false;
System.out.println("Fatal Error");
while (true){
}
}
else{
JMove AIMove = JChessEngine.getAllValid(types,colors,moved,lastMove,!gameTurn).get(AImoveIndex);
AIMove.makeMove(types,colors,moved);
lastMove = AIMove;
validMoves = JChessEngine.getAllValid(types,colors,moved,lastMove,gameTurn);
}
waitingOnComputer = false;
parent.repaint();
}
catch(Exception e){
e.printStackTrace();
}
Sometimes, the external process will get stuck on IO, trying to write to the console. If the console buffer is full, the next printf will block.
How much text is it writing to the console?
Try moving your engine.waitFor() after the part where you read all the input from it.
An alternative would be to have the external process write to a temp file, and then you read the temp file.
Maybe remove
while (true){
}
If your AImoveIndex == -1, your program will enter in a never ending loop.

Java - Use Input and OutputStream of ProcessBuilder continuously

I want to use an external tool while extracting some data (loop through lines).
For that I first used Runtime.getRuntime().exec() to execute it.
But then my extraction got really slow. So I am searching for a possibility to exec the external tool in each instance of the loop, using the same instance of shell.
I found out, that I should use ProcessBuilder. But it's not working yet.
Here is my code to test the execution (with input from the answers here in the forum already):
public class ExecuteShell {
ProcessBuilder builder;
Process process = null;
BufferedWriter process_stdin;
BufferedReader reader, errReader;
public ExecuteShell() {
String command;
command = getShellCommandForOperatingSystem();
if(command.equals("")) {
return; //Fehler! No error handling yet
}
//init shell
builder = new ProcessBuilder( command);
builder.redirectErrorStream(true);
try {
process = builder.start();
} catch (IOException e) {
System.out.println(e);
}
//get stdout of shell
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//get stdin of shell
process_stdin = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
System.out.println("ExecuteShell: Constructor successfully finished");
}
public String executeCommand(String commands) {
StringBuffer output;
String line;
try {
//single execution
process_stdin.write(commands);
process_stdin.newLine();
process_stdin.flush();
} catch (IOException e) {
System.out.println(e);
}
output = new StringBuffer();
line = "";
try {
if (!reader.ready()) {
output.append("Reader empty \n");
return output.toString();
}
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
return output.toString();
}
if (!reader.ready()) {
output.append("errReader empty \n");
return output.toString();
}
while ((line = errReader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
System.out.println("ExecuteShell: error in executeShell2File");
e.printStackTrace();
return "";
}
return output.toString();
}
public int close() {
// finally close the shell by execution exit command
try {
process_stdin.write("exit");
process_stdin.newLine();
process_stdin.flush();
}
catch (IOException e) {
System.out.println(e);
return 1;
}
return 0;
}
private static String getShellCommandForOperatingSystem() {
Properties prop = System.getProperties( );
String os = prop.getProperty( "os.name" );
if ( os.startsWith("Windows") ) {
//System.out.println("WINDOWS!");
return "C:/cygwin64/bin/bash";
} else if (os.startsWith("Linux") ) {
//System.out.println("Linux!");
return"/bin/sh";
}
return "";
}
}
I want to call it in another Class like this Testclass:
public class TestExec{
public static void main(String[] args) {
String result = "";
ExecuteShell es = new ExecuteShell();
for (int i=0; i<5; i++) {
// do something
result = es.executeCommand("date"); //execute some command
System.out.println("result:\n" + result); //do something with result
// do something
}
es.close();
}
}
My Problem is, that the output stream is always empty:
ExecuteShell: Constructor successfully finished
result:
Reader empty
result:
Reader empty
result:
Reader empty
result:
Reader empty
result:
Reader empty
I read the thread here: Java Process with Input/Output Stream
But the code snippets were not enough to get me going, I am missing something. I have not really worked with different threads much. And I am not sure if/how a Scanner is of any help to me. I would really appreciate some help.
Ultimatively, my goal is to call an external command repeatetly and make it fast.
EDIT:
I changed the loop, so that the es.close() is outside. And I wanted to add, that I do not want only this inside the loop.
EDIT:
The problem with the time was, that the command I called caused an error. When the command does not cause an error, the time is acceptable.
Thank you for your answers
You are probably experiencing a race condition: after writing the command to the shell, your Java program continues to run, and almost immediately calls reader.ready(). The command you wanted to execute has probably not yet output anything, so the reader has no data available. An alternative explanation would be that the command does not write anything to stdout, but only to stderr (or the shell, maybe it has failed to start the command?). You are however not reading from stderr in practice.
To properly handle output and error streams, you cannot check reader.ready() but need to call readLine() (which waits until data is available) in a loop. With your code, even if the program would come to that point, you would read only exactly one line from the output. If the program would output more than one line, this data would get interpreted as the output of the next command. The typical solution is to read in a loop until readLine() returns null, but this does not work here because this would mean your program would wait in this loop until the shell terminates (which would never happen, so it would just hang infinitely).
Fixing this would be pretty much impossible, if you do not know exactly how many lines each command will write to stdout and stderr.
However, your complicated approach of using a shell and sending commands to it is probably completely unnecessary. Starting a command from within your Java program and from within the shell is equally fast, and much easier to write. Similarly, there is no performance difference between Runtime.exec() and ProcessBuilder (the former just calls the latter), you only need ProcessBuilder if you need its advanced features.
If you are experiencing performance problems when calling external programs, you should find out where they are exactly and try to solve them, but not with this approach. For example, normally one starts a thread for reading from both the output and the error stream (if you do not start separate threads and the command produces large output, everything might hang). This could be slow, so you could use a thread pool to avoid repeated spawning of processes.

Java Process.waitFor() and Readline hangs

First, this is my code :
import java.io.*;
import java.util.Date;
import com.banctecmtl.ca.vlp.shared.exceptions.*;
public class PowershellTest implements Runnable {
public static final String PATH_TO_SCRIPT = "C:\\Scripts\\ScriptTest.ps1";
public static final String SERVER_IP = "XX.XX.XX.XXX";
public static final String MACHINE_TO_MOD = "MachineTest";
/**
* #param args
* #throws OperationException
*/
public static void main(String[] args) throws OperationException {
new PowershellTest().run();
}
public PowershellTest(){}
#Override
public synchronized void run() {
String input = "";
String error = "";
boolean isHanging = false;
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("powershell -file " + PATH_TO_SCRIPT +" "+ SERVER_IP +" "+ MACHINE_TO_MOD);
proc.getOutputStream().close();
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
proc.waitFor();
String line;
while (!isHanging && (line = bufferedreader.readLine()) != null) {
input += (line + "\n");
Date date = new Date();
while(!bufferedreader.ready()){
this.wait(1000);
//if its been more then 1 minute since a line has been read, its hanging.
if(new Date().getTime() - date.getTime() >= 60000){
isHanging = true;
break;
}
}
}
inputstream.close();
inputstream = proc.getErrorStream();
inputstreamreader = new InputStreamReader(inputstream);
bufferedreader = new BufferedReader(inputstreamreader);
isHanging = false;
while (!isHanging && (line = bufferedreader.readLine()) != null) {
error += (line + "\n");
Date date = new Date();
while(!bufferedreader.ready()){
this.wait(1000);
//if its been more then 1 minute since a line has been read, its hanging.
if(new Date().getTime() - date.getTime() >= 60000){
isHanging = true;
break;
}
}
}
inputstream.close();
proc.destroy();
} catch (IOException e) {
//throw new OperationException("File IO problem.", e);
} catch (InterruptedException e) {
//throw new OperationException("Script thread problem.",e);
}
System.out.println("Error : " + error + "\nInput : " + input);
}
}
I'm currently trying to run a powershell script that will start/stop a vm (VMWARE) on a remote server. The script work from command line and so does this code. The thing is, I hate how I have to use a thread (and make it wait for the script to respond, as explained further) for such a job. I had to do it because both BufferedReader.readline() and proc.waitFor() hang forever.
The script, when ran from cmd, is long to execute. it stall for 30 sec to 1 min from validating authentification with the server and executing the actual script. From what I saw from debugging, the readline hang when it start receiving those delays from the script.
I'm also pretty sure it's not a memory problem since I never had any OOM error in any debugging session.
Now I understand that Process.waitFor() requires me to flush the buffer from both the error stream and the regular stream to work and so that's mainly why I don't use it (I need the output to manage VM specific errors, certificates issues, etc.).
I would like to know if someone could explain to me why it hangs and if there is a way to just use the typical readline() without having it to hang so hard. Even if the script should have ended since a while, it still hang (I tried to run both the java application and a cmd command using the exact same thing I use in the java application at the same time, left it runingfor 1h, nothing worked). It is not just stuck in the while loop, the readline() is where the hanging is.
Also this is a test version, nowhere close to the final code, so please spare me the : this should be a constant, this is useless, etc. I will clean the code later. Also the IP is not XX.XX.XX.XXX in my code, obviously.
Either explanation or suggestion on how to fix would be greatly appreciated.
Ho btw here is the script I currently use :
Add-PSSnapin vmware.vimautomation.core
Connect-VIServer -server $args[0]
Start-VM -VM "MachineTest"
If you need more details I will try to give as much as I can.
Thanks in advance for your help!
EDIT : I also previously tested the code with a less demanding script, which job was to get the content of a file and print it. Since no waiting was needed to get the information, the readline() worked well. I'm thus fairly certain that the problem reside on the wait time coming from the script execution.
Also, forgive my errors, English is not my main language.
Thanks in advance for your help!
EDIT2 : Since I cannot answer to my own Question :
Here is my "final" code, after using threads :
import java.io.*;
public class PowershellTest implements Runnable {
public InputStream is;
public PowershellTest(InputStream newIs){
this.is = newIs;
}
#Override
public synchronized void run() {
String input = "";
String error = "";
try {
InputStreamReader inputstreamreader = new InputStreamReader(is);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line;
while ((line = bufferedreader.readLine()) != null) {
input += (line + "\n");
}
is.close();
} catch (IOException e) {
//throw new OperationException("File IO problem.", e);
}
System.out.println("Error : " + error + "\nInput : " + input);
}
}
And the main simply create and start 2 thread (PowerShellTest instances), 1 with the errorStream and 1 with the inputStream.
I believe I made a dumb error when I first coded the app and fixed it somehow as I reworked the code over and over. It still take a good 5-6 mins to run, which is somehow similar if not longer than my previous code (which is logical since the errorStream and inputStream get their information sequentially in my case).
Anyway, thanks to all your answer and especially Miserable Variable for his hint on threading.
First, don't call waitFor() until after you've finished reading the streams. I would highly recommend you look at ProcessBuilder instead of simply using Runtime.exec, and split the command up yourself rather than relying on Java to do it for you:
ProcessBuilder pb = new ProcessBuilder("powershell", "-file", PATH_TO_SCRIPT,
SERVER_IP, MACHINE_TO_MOD);
pb.redirectErrorStream(true); // merge stdout and stderr
Process proc = pb.start();
redirectErrorStream merges the error output into the normal output, so you only have to read proc.getInputStream(). You should then be able to just read that stream until EOF, then call proc.waitFor().
You are currently waiting to complete reading from inputStream before starting to read from errorStream. If the process writes to its stderr before stdout maybe you are getting into a deadlock situation.
Try reading from both streams from concurrently running threads. While you are at it, also remove proc.getOutputStream().close();. It shouldn't affect the behavior, but it is not required either.

Debugging user event in a Java GUI Application

I am using a Java Project that gives an user interface for doing some user events. It is not being executed as Runnable thread in main() as in most Swing/Gui applications. Rather it has several class and form files in the source code and is run from command line using another Java program.
But when I am trying to read a certain file by clicking on some input button, the system fails to read the file. The system writes the custom error message into a file named log.txt saved within the project folder.
I have tried
1. Setting breakpoints (the application does not stop at breakpoint)
2. Doing console prints i.e. System.out.println (there is no print on console)
So both the ways of debugging has failed. I am using Eclipse 3.5.2 SDK (Galileo). How can I debug the user events on my applicattion?
The outline of the source class DataImportPanel in project DDMT is listed below. It is giving an exception in the method DataImportPanel.openHeteroFile(File).
DDMT.core.DataImportPanel
...
DDMT.core.DataImportPanel.heteroDistributionModel
...
DDMT.core.DataImportPanel.initComponents()
DDMT.core.DataImportPanel.initComponents().new ActionListener() {...}
...
DDMT.core.DataImportPanel.initComponents().new MouseAdapter() {...}
DDMT.core.DataImportPanel.initComponents().new ActionListener() {...}
DDMT.core.DataImportPanel.jButton2ActionPerformed(ActionEvent)
...
DDMT.core.DataImportPanel.jButton3ActionPerformed(ActionEvent)
DDMT.core.DataImportPanel.openHeteroFile(File)
DDMT.core.DataImportPanel.jButton8ActionPerformed(ActionEvent)
DDMT.core.DataImportPanel.openFile(File)
DDMT.core.DataImportPanel.jButton15ActionPerformed(ActionEvent)
DDMT.core.DataImportPanel.jRadioButton1ActionPerformed(ActionEvent)
DDMT.core.DataImportPanel.buttonGroup1
...
DDMT.core.DataImportPanel.jButton8
DDMT.core.DataImportPanel.jButton9
DDMT.core.DataImportPanel.jLabel1
...
DDMT.core.DataImportPanel.jList1
...
DDMT.core.DataImportPanel.jPanel1
...
DDMT.core.DataImportPanel.jRadioButton1
...
DDMT.core.DataImportPanel.jScrollPane1
...
DDMT.core.DataImportPanel.jTabbedPane1
DDMT.core.DataImportPanel.DistributionTypes
DDMT.core.DataImportPanel.DoubleCellRenderer
Here is the openHeteroFile which is throwing the Data Import exception
private void openHeteroFile(File f)
{
File file = null;
try{
file = f;
file.createNewFile();
FileReader reader = new FileReader(file);
BufferedReader bReader = new BufferedReader(reader);
//The vector that holds the number of columns
attributeNames = new ArrayList<String>();
//Read in the number of pairs
String line = bReader.readLine();
//load the file
heteroDistributionModel = new DefaultListModel();
line = bReader.readLine();
while( line != null )
{
//Set up the RegEx matches
heteroDistM = heteroDistP.matcher(line);
firstM = firstP.matcher(line);
firstM.find();
String output1 = firstM.group()+" (";
for( int j = 0; j< nodeTypes[0].length; j++)
{
if( controlClass.nodes[Integer.parseInt(firstM.group())].getNodeType().equals( nodeTypes[1][j]) )
{
output1 = output1+nodeTypes[0][j]+")";
}
}
String output2 = new String();
while( heteroDistM.find() )
{
attributeNames.add(heteroDistM.group(1));
output2 = output2 + " "+heteroDistM.group(1);
}
heteroDistributionModel.addElement(new String[]{output1, output2});
line = bReader.readLine();
}
for (String attr : attributeNames)
System.out.println(attr); //debug
jList3.setModel(heteroDistributionModel);
jList3.setCellRenderer(new DoubleCellRenderer());
bReader.close();
reader.close();
}catch(IOException ex)
{
controlClass.showError("Data Import: Error: File "+file.getPath()+" is not a valid Heterogeneous data file!");
}catch(Exception ex)
{
ex.printStackTrace(); //debug
controlClass.showError("Data Import: Error: Unknown problem reading file "+file.getPath()+"!");
}
}
There is a little green ladybug right next to the run button that starts the debugger.
I would make sure the proper calls are being made. Also check your brackets, breaks, and returns to make sure the code is actually being read. Please post a SSCCE (Short, Self Contained, Correct Example) so we can view your code to help you out better.
Edit (after OP added some code)
I'm pretty sure your issue is where you file.createNewFile();

input.read() func. lock in the while loop

After connecting to server, I run some commands on server and then trying to take the server knowledge to console with;
while(i!=-1){
String c="";
String line = "";
try {
while ((i = input.read()) != 10 && i!=-1) {
bx[0] = (byte) i;
c = new String(bx);
line = line + c ;
System.out.print(c);
}
} catch (IOException e2) {
e2.printStackTrace();
}
File outfile = new File("calltrak.txt");
boolean append = true;
try
{
if (!outfile.exists())
{
append = false;
}
FileWriter fout1 = new FileWriter("calltrak.txt",append);
PrintWriter fileout = new PrintWriter(fout1,true);
fileout.println(line);
fileout.flush();
fileout.close();
} catch (IOException e1) {
e1.printStackTrace();
}
disp.append(line);
}
But the problem is when the program read all lines from server windows, in server it waits to new input and my prog still tring to read the line and so it locked... How can I solve this problem... (Note:Using a timer isn't a way to solve because the lines which the program read can be 100 line or 100000 and sometimes server can work slow) (In the code "disp" is Jpanel name)
I solved this problem with using paralel thread. With starting Inputstream read method I also started another thread and put inside of it a timer.If read method wait more than 5 seconds, other thread sen -1 to first loop and so loop terminated.
There are several problems performance wise with your code, but to answer your question you should let the server send a EndOfText 0x3 or EndOfTransmission 0x4 at the end see AsciiTable this way you can terminate then.

Categories