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
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 have a library that needs to create a schema in MySQL from Java. Currently, I have a dump of the schema that I just pipe into the mysql command. This works okay, but it is not ideal because:
It's brittle: the mysql command needs to be on the path: usually doesn't work on OSX or Windows without additional configuration.
Also brittle because the schema is stored as statements, not descriptively
Java already can access the mysql database, so it seems silly to depend on an external program to do this.
Does anyone know of a better way to do this? Perhaps...
I can read the statements in from the file and execute them directly from Java? Is there a way to do this that doesn't involve parsing semicolons and dividing up the statements manually?
I can store the schema in some other way - either as a config file or directly in Java, not as statements (in the style of rails' db:schema or database.yml) and there is a library that will create the schema from this description?
Here is a snippet of the existing code, which works (when mysql is on the command line):
if( db == null ) throw new Exception ("Need database name!");
String userStr = user == null ? "" : String.format("-u %s ", user);
String hostStr = host == null ? "" : String.format("-h %s ", host);
String pwStr = pw == null ? "" : String.format("-p%s ", pw);
String cmd = String.format("mysql %s %s %s %s", hostStr, userStr, pwStr, db);
System.out.println(cmd + " < schema.sql");
final Process pr = Runtime.getRuntime().exec(cmd);
new Thread() {
public void run() {
try (OutputStream stdin = pr.getOutputStream()) {
Files.copy(f, stdin);
}
catch (IOException e) { e.printStackTrace(); }
}
}.start();
new Thread() {
public void run() {
try (InputStream stdout = pr.getInputStream() ) {
ByteStreams.copy(stdout, System.out);
}
catch (IOException e) { e.printStackTrace(); }
}
}.start();
int exitVal = pr.waitFor();
if( exitVal == 0 )
System.out.println("Create db succeeded!");
else
System.out.println("Exited with error code " + exitVal);
The short answer (as far as i know) is no.
You will have to do some parsing of the file into separate statements.
I have faced the same situation and you can find many questions on this topic here on SO.
some like here will show a parser. others can direct to tools Like this post from apache that can convert the schema to an xml format and then can read it back.
My main intention when writing this answer is to tell that I chose to use the command line in the end.
extra configuration: maybe it is an additional work but you can do it by config or at runtime based on the system you are running inside. you do the effort one time and you are done
depending on external tool: it is not as bad as it seems. you have some benefits too.
1- you don't need to write extra code or introduce additional libraries just for parsing the schema commands.
2- the tool is provided by the vendor. it is probably more debugged and tested than any other code that will do the parsing.
3- it is safer on the long run. any additions or changes in the format of dump that "might" break the parser will most probably be supported with the tool that comes with the database release. you won't need to do any change in your code.
4- the nature of the action where you are going to use the tool (creating schema) does not suggest frequent usage, minimizing the risk of it becoming a performance bottle neck.
I hope you can find the best solution for your needs.
Check out Yank, and more specifically the code examples linked to on that page. It's a light-weight persistence layer build on top of DBUtils, and hides all the nitty-gritty details of handling connections and result sets. You can also easily load a config file like you mentioned. You can also store and load SQL statements from a properties file and/or hard code the SQL statements in your code.
Given 3 web applications under test with given URLs:
www.A.com
www.B.com
www.C.com
How do I proceed to design a way using Selenium to run a single TestNG test against these three browsers and print out the results.
Current Strategy:
I have a java class with a main method, a properties file containing the the 3 urls listed above.
In this class i have a while loop that parses these properties file like below snippet, and for each url, programmatically calls an ant task that automates the build from compilation to test-run to result archiving. The problem is that after the first run completes, it doesn't return to the while loop to do it again. You might ask why i want to run it three times. The idea as already explained is to be able to run a suite of tests against multiple websites automatically and printout results without intervention. Code Snippet
try {
reader = new BufferedReader(new FileReader(new File(filename)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
while((line=reader.readLine()) != null){
//call ant target to archive result
userprops.setProperty("url", line);
org.apache.tools.ant.Main.start(target, userprops, loader);
}
}catch (IOException e) {
e.printStackTrace();
}
I hope somebody understands what am trying to do and can help me understand why the while loop terminates after the first test run. Also maybe can offer another easier strategy with TestNG.
thanks Guys. Y.ou guys Rock!!
It seems to me that if you are using ANT you shouldn't need your class. I would just use three targets and assign the different properties within those targets.
This code has lot of trouble for my AIR 2.0 Native process which I tried to launch Java from AIR application, then the Java.exe terminate itself in the Windows Task manager, I found that new MidiTest() was the caused. Is there a better solution for new instance?
public static void main(String[] arg) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (!(speed.equals(speed_stop))) {
try {
speed = in.readLine();
if(!(Global.newPlayer.equals("1"))){new MidiTest();}
} catch (IOException e) {
System.err.println("Exception while reading the input. " + e);
}
}
}
private MidiPlayer player;
public MidiTest() {
System.out.println("Start player");
// /*
}
There is no alternative to new.
This is the only way to instantiate an object. Even if you use reflection, you're still calling the constructor. You need to track down the problem. Find the exact exception that's being caused, and the exact line number, and then see what you need to do to fix that problem.
I can see that you didn't provide a complete copy of your code. There's an open comment before the close brace, and it's not right. So that means we can't help you any further with the information we have.
No, the only other option for creating a new instance of your class would be using reflection, which is a much more obscure and error prone choice than new. It should not be used unless one really needs to. And even that is loading the class and calling the object's constructor in the end, exactly the same way as new.
I suspect the problem lies somewhere in code you haven't shown to us. Does MidiTest have any (static or nonstatic) initializer blocks? Is that println() statement really the only code in its constructor?
Of course, it helped if you traced down what is the exact error/exception causing the termination and where exactly does it originate from :-)
How can I "eject" a volume with Java, cross platform?
I have a program that does some operations on a removable drive (USB memory card reader), and once it's done, I want the program to eject/unmount/remove (depending which os lingo we're talking in) the memory card.
Is there a reliable cross-platform method of doing this?
Probably isn't the answer you're looking for, but...
No.
To my knowledge, there isn't an established single-platform way of doing this. For that matter, I've never come across a Java way of doing this. A rather scary C# CodeProject does allow ejecting devices, but only on Windows.
The various, depressingly poor, Java USB libraries don't even hint at ejecting devices. They don't work across all platforms, so even if they did it wouldn't help you.
My suggestion: gin up some scripts or executables for each platform, and then just spin up a Process as needed.
A litle late response but i thought it was worth sharing...
Since the default Java API does not come with this feature on it, you could use external libraries as mentioned above, however i personally found it much more convenient (for windows) to have a third party exe file in the jar's classpath, extract it in the temp folder, execute it when needed and then remove it once the aplication is done with it.
As a third party program i used this which is a CLI only program that can do a few tricks with connected devices, and then used this code:
FileUtils.copyInputStreamToFile(MyClass.class.getClassLoader().getResourceAsStream(program),TEMP_EJECT_PROGRAM);
to export it to the temp file location (Using ApacheIO, you can definately do without it), and this code:
private void safelyRemoveDrive(final String driveLetter) {
new Thread(new Runnable() {
public void run() {
if (TEMP_EJECT_PROGRAM.exists()) {
System.out.println("Removing " + driveLetter);
try {
Process p = Runtime.getRuntime()
.exec("\"" + TEMP_EJECT_PROGRAM.toString() + "\" " + driveLetter + " -L");
p.waitFor();
Scanner s = new Scanner(p.getInputStream());
while (s.hasNextLine())
System.out.println(s.nextLine());
s.close();
System.out.println("Removed " + driveLetter + ".");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
to remove the drive. The pieces of code above are definately not suited for all aplications and the second one in perticular is not the greatest, there are other much better ways to do it than spawning an anonymus thread... Still however you get the idea behind it :)
Lastly, I sugest you inform the user appropriately and ask for their concent before executing any third-party software in their machine...
I hope this was helpful :-)