Hi I'm writing my first Java app and I've got a few Testcases (*.tc files) I want to direct to the app via this script:
for f in `ls *.tc`; do
echo "Current Testcase: $f"
x=${f%.*}
java Main < $x.tc > $x.out
if diff "$x.out" "$x.should"; then
echo "passed testcase $f"
let PASSED=PASSED+1
else
echo "failed testcase $f"
let FAILED=FAILED+1
fi
done
The Problem is I can't quite figure out why as soon as the tc file contains more than one line the app goes nuts. For example: quit.tc contains
quit
and works just like when I manually enter "quit", therfore the testcase passes.
However when I write another tc: quit2.tc which contains
lala
test
quit
The app quits after the first command (because the readString function seems to return null afterwards).
Here is the function responsible for reading:
public String readString(){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String answer = null;
try {
answer = br.readLine();
return answer;
}
catch(IOException ioe) {
System.out.println("IO Error");
}
return answer;
}
I dont know why or when this function returns null when I redirect to the app, which seems to be the problem. Can you help out so I can get the tc script working? thx
If you're new to java, and you still shape your style and way of doing things, I will recommend you 2 tips:
1) use Scanner to read your input. Using nextLine() method of the Scanner object is probably what you're looking for.
2) design your code, so that it's testable via JUnit.
Still, in your readString() method, remove the return answer; from the try block.
UPDATE: try to implement the following in your function:
a) while the scanner instance hasNextLine() is true ->
b) call scanner instance nextLine() method ->
c) parse the line, and see if it equals 'quit' ->
d) implement the corresponding logical if cases.
Your problem is BufferedReader: It will read the whole file at once (for performance reasons).
Since you create a new BufferedReader each time readString() is called, the first reader will swallow most of the file (or all of it) and the second reader will hit end-of-file.
The solution is to put the reader into a field, create it once and then always use the same reader to call readLine()
Plus you never close the reader.
Java will forget unused objects but you must properly close OS resources like FileInputStreams
Related
I have a Matlab script that makes many system calls through the system() function.
However, I noticed that the function is very slow (has a lot of overhead). For example, the call
tic;system('echo');toc;
takes on average 0.08 seconds. With lots of system calls overhead becomes unacceptable.
I tried to replace the calls with calls to Java (which I do not know, I am just copying and pasting from somewhere else), as follows
runtime=java.lang.Runtime.getRuntime();
process=runtime.exec('commandStringThatNeedsToBeExecuted');
status=process.waitFor();
When it works, it works nicely and the overhead is significantly reduced. However, I have two problems.
First problem: for some commands execution fails (but it does not fail with calls to system()), depending on the program I call. In particular (but this is probably irrelevant), when I make calls to pdflatex, everything works fine, while when I make calls to ImageMagick's convert, execution fails. So, in order to understand these differences in behavior, my first question is: what are the main differences between a Matlab system() call and a system call through Java?
Second problem: how do I get the output of the command (I mean what would be displayed on screen if, for example, the command was executed in a DOS command window) that I can get from the second output argument of the system() function?
To get the output, try this:
p = java.lang.ProcessBuilder({'cmd', 'arg1', 'arg2'}).start();
reader = java.io.BufferedReader(java.io.InputStreamReader(p.getInputStream()));
str = char(java.util.Scanner(reader).useDelimiter('\A').next());
You can replace the last line with this:
...
sb = java.lang.StringBuilder();
while true;
line = reader.readLine();
if isnumeric(line); % Test for NULL
break;
else
sb.append(sprintf('%s\n',char(line)));
end;
end
str = char(sb.toString());
The first is faster if there is a lot of output (matlab's system() is very slow in this case), while the second is clearer and more flexible.
As for why it sometimes fails, I'm not sure. Are you constructing the command string in the same way? Do identical command strings sometimes work and sometimes not work? Are you fiddling with the environment?
The differences are as far as i know, system can actively execute cmd commands (Windows) whereas for runtime.exec() commands you have to insert cmd /c beforehand.
To read the output of the process, do the following:
p.waitFor();
try (BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
final StringBuilder string = new StringBuilder();
String line;
try {
while (input.ready() && (line = input.readLine()) != null) {
string.append(line + "\n");
}
} catch (IOException e) {}
return string.toString();
} catch (Exception ex) {
ex.printStackTrace();
}
This will connect to the outputstream of the process and read it line by line into the stringbuilder.
I'm working on a project where I need to run a lot of shell commands and invoke external tools from matlab. This slowness issue caused me a lot of pain.
I've found the above ProcessBuilder-based approach very helpful (thanks!) but still needed to tweak various things.
Here's my implementation, hope it's useful for future visitors coming here...
https://github.com/avivrosenberg/matlab-jsystem
I am writing a program in Java that needs to use terminal command to work.
My function basically looks like this :
public void sendLoginCommand() throws IOException
{
System.out.println("\n------------Sending Login Command------------\n");
String cmd="qskdjqhsdqsd";
Runtime rt = Runtime.getRuntime();
Process p=rt.exec(cmd);
}
public Process sendPassword(String password) throws IOException
{
System.out.println("\n------------Sending Password------------\n");
String cmd=password;
Runtime rt = Runtime.getRuntime();
Process p=rt.exec(cmd);
return p;
}
public void login(String password) throws IOException
{
sendLoginCommand();
Process p = sendPassword(password);
System.out.println("\n------------Reading Terminal Output------------\n");
Reader in = new InputStreamReader(p.getInputStream());
in = new BufferedReader(in);
char[] buffer = new char[20];
int len = in.read(buffer);
String s = new String(buffer, 0, len);
System.out.println(s);
if(s.equals("Password invalid.")) loggedIn=false;
else loggedIn=true;
}
Here, the program sends correctly th p4 login command, but then, the terminal asks for a password.
When I use the same lines that with the sendLoginCommand(), the program returns an error.
Apparently, we can send only standard commands throught Process.
I was hoping that someone knew how to send a normal string to the terminal
Thank you in advance
Your immediate problem is that you are starting separate processes for each of the 'commands' you are invoking. The password 'command' is being issued to a process that is totally unaware of the previous 'login' command.
Having said that, your more dire problem is a serious misunderstanding of what the Process class is used for and how to interact with external programs from within Java.
Here's one tutorial that may help further your education on the topic, I would advise Googling for others.
I have found the answer to my question.
The problem was that the second response of the terminal was in fact in the first one, and the password had to be sent in the middle of it.
Here is the code (I agree, my explanation is a little vague) :
String s="";
Process p = Runtime.getRuntime().exec("p4 login");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
char a=(char)in.read();
while(a>0 && a<256)
{
a=(char)in.read();
if(nb==14) new PrintWriter(p.getOutputStream(),true).println(password);
if(nb>16) s=s+a;
nb++;
}
if(s.startsWith("User")) loggedIn=true;
else loggedIn=false;
In order to communicate with a process, you don't start another process but write to its stdin. There's actually code in there that tries to do such a thing. Have sendLoginCommand return the created process; delete all code in sendPassword, in fact delete the whole method. In your main code write your password to the process's output stream. So what I'm saying is
new PrintWriter(sendLoginCommand().getOutputStream()).println(password);
As a side note, i strongly advice to use a pre-packaged library that already encapsulates all the technical stuff about the process communication in Java.
A good library about that is commons-exec (http://commons.apache.org/exec/.
It comes with command line helper, background thread to read the sysout/syserr output, an optional watchdog to kill the process after a given amount of time, and so on (it works of course on nearly all os).
I am trying to access SVN through the process command in Java as part of a larger GUI to see what files are on the SVN. After much research, I have significantly refined my methods, however I still cannot accomplish it. If I run the code in the GUI, it just hangs. To discover what that problem was, I simplified it and ran it as a console program. When I ran it there, it displayed a request for my GNOME keyring. My code enters the password but the console does not seem to accept it. My code follows:
public class SvnJavaTest{
public static void main(String[] args){
try {
String[] commands = {"svn", "ls", "https://svnserver"};
Process beginProcess = Runtime.getRuntime().exec(commands, null, new File("/home/users/ckorb/Desktop"));
BufferedReader br = new BufferedReader(new InputStreamReader(beginProcess.getInputStream()));
BufferedWriter write = new BufferedWriter(new OutputStreamWriter(beginProcess.getOutputStream()));
write.write("password");
write.flush();
String line=br.readLine();
while (line != null){
System.out.println(line);
line =br.readLine();
}
br.close();
write.close();
beginProcess.waitFor();
} catch (IOException e1) {
e1.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
I don't get any errors running this and if I type in my password manually into the console and then run it, it works because it remembers my password. I have looked and found that there are some packages that would automatically enter my keyring on login but that isn't really an option. Thank you very much.
The main problem with a solution like this is that you don't really have control over stdin and stdout. A malicious person can wrap the svn command with a shell script that makes a copy of the stdin (thereby capturing all the passwords your program transmits). While shell's flexibility makes it great in so many ways, it is the same flexibility that you are connecting to, and you'd better be comfortable with it (and it's consequences).
That is the real reason why it is better to use a Java API to use the client, there's a much smaller chance of injecting code which captures sensitive data (and better error reporting).
Use the SVN Kit library instead.
Better to use svn java API (there are several, I am not sure which one is better), it's more straightforward solution.
Answering you question - you could provide auth info in the url: https://username:password#svnserver
I am trying to do a programming exercise here making a client and a server that work with sockets.For the communication between them i use PrintWriter and InputReader.What im stuck with is : How can i check if the Server is trying to send something to the client,while the client is waiting for input ? At this point the client loop is something like this :
do {
outToServer.println(inFromUser.readLine());
String fromServer=inFromServer.readLine();
if(fromServer.equals("OK")){
clientSocket.close();
}else{
System.out.println(fromServer);
}
} while (!clientSocket.isClosed());
The problem is that in some cases the server needs to print multiple lines ,before needed an input again.Instead it prints 1 line then ill have to type something,then another line comes etc . Is there a way to get around that problem ? Thanks .
So you're going to need to encapsulate the
outToServer.readLine();
in a while loop that has a boolean conditional similar to a hasNext() function. You may want to set it up as follows:
String x = outToServer.readLine();
//while x doesn't equal whatever readLine would return if there's nothing to read
//I'm not sure if this is a null String or not
while(x!=null){
System.out.print(x);//print it however you wish
String x = outToServer.readLine();
}
And then do something similar for inFromServer if needed.
http://pastebin.com/m5fa7685e
It seems to fail when getting f3.. Output is:
not ready
File is null
Exception in thread "main" java.lang.NullPointerException
at BuabFile.parseBUAB(BuabFile.java:93)
at AddressBook.createBrowseForm(AddressBook.java:232)
at AddressBook.(AddressBook.java:51)
at Main.main(Main.java:4)"
But not before then - no file not found errors or anything...
My guess would be that the parseBUAB() method receives a "null" argument. Which means that it could be that it is the AddressBook class is responsible for the error.
It looks like you forgot to assign a value to BuabFile.file static field. You may want to add this to the end of your readFile() method:
BuabFile.file = f3;
I am guessing your AddressBook.createBrowseForm method looks something like this:
String filename = ...;
BuabFile buab = new BuabFile(filename);
buab.readFile();
ArrayList<String> buabLines = buab.returnFile(); // Returns null because readFile() never assigned a value to BuabFile.file
ArrayList<Buab> buabList = buab.parseBUAB(buabLines);
From all I can see, you just call parseBUAB(..) with a null value. I can't see the call to that method so you have to check the rest of your code.
For your 'not ready' output, which is created because your BufferedReader f3 is 'not ready', the API says
True if the next read() is guaranteed not to block for input, false otherwise.
Maybe you just call it too fast and the file is not loaded yet. Play with Thread.sleep() before calling ready() on the stream. Maybe a some-milliseconds blocking is just normal for File I/O.
And third - if f3 is the BufferedReader you want to keep, you have to assign it to the member file in the readFile() method. But now that's all I found ;)
I'm confused further but have found an answer sort of - I'm using windows 7 and have tried it on a windows xp computer and the code compiles fine and reads in the file (other errors you lot have noted are to be changed anyway through development - this was just one stick in the way...).
I'm wondering if there is some Windows 7 error with eclipse and opening/reading files...