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
Related
I'm working on a big system that interconnects different platforms in different languages. Two of these platforms are a RoR website and a Java application whose task is to insert data (no matter where from) to the RoR PostgreSQL database. Currently, I was using simple SQL queries to insert, for example, a product. This is working right, however, I can't take advantage of framework's included tools like timestamps and model callbacks.
The question is, is there a way to, instead of executing those SQL queries, execute rails console commands, considering my Java application runs completely apart the RoR application? If you need to know, I'm using rails 4.
Please excuse my english and thank you in advance.
I don't think that is a good idea at all. But you can achieve this if the java application connects to the same machine RoR is running. You can then use rails runner or you can execute some rake task. The use of rails runner is really simple, check out this example from the official documentation from http://guides.rubyonrails.org/command_line.html#rails-runner
$ bin/rails runner -e staging "Model.long_running_method"
I did as #IvanT suggested, however despite the diverse approaches I can't make it work, here's one of the codes I tried:
String railsCmd = "Product.where(:category_id => 9).each { |p| p.update_attribute(:brand, 'NO BRAND') }";
String wholeCommand = "rails runner -e development \"" + railsCmd + "\"";
StringBuilder output = new StringBuilder();
Process p = Runtime.getRuntime().exec(wholeCommand, null, new File("/path/to/rails/project/bin"));
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine())!= null) {
output.append(line).append("\n");
}
System.out.println(output.toString());
It takes a couple seconds to process, as it's doing something, but there is no change in products themselves. I tried the command directly in the terminal and works good.
I would also like to know why you think it's not a good idea.
Thank you for your time.
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'm making an application which is like windows task manager. For that, I need the list of all opened applications (not processes), which are shown in taskbar.
Here are some sources to look into:
http://www.daniweb.com/web-development/jsp/threads/93197
http://java.ittoolbox.com/groups/technical-functional/java-l/java-code-required-to-access-task-manager-569041
http://www.sqaforums.com/showflat.php?Cat=0&Number=658713&an=0&page=6
Looks like you'll be using the Runtime class.
None of your links CFL_Jeff says anything of how to get active application windows (which I assume is what you want?
Don't think this can be accomplished with java or a simple windows commandline.
Here might be a way to do it in C#:
Get the list of opened windows C#
Or you might have to take a look here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ff468919%28v=vs.85%29.aspx
An emergency solution might be to use the "tasklist /v" command and get all processes that have a "windowtitle" that differ from "I/T"(might be locale dependent), but that will give you tray icons aswell I'm afraid.
Edit:
To get the tasklist, you can use the following:
try
{
Process p = Runtime.getRuntime().exec("cmd /c tasklist /v");
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
String input;
while ((input = stdInput.readLine()) != null)
{
output += input;
}
stdInput.close();
}
catch(Exception k){JOptionPane.showMessageDialog(null, k.getMessage());}
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
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