How to retrieve db2 command output from within Java program - java

I am unable to retrieve the output of "db2 list db directory" command in my Java program. Basically, what I am trying to do is this:-
A combo box is populated with db2 instances in the local system
User selects a particular instance from the combo box
A new Process is run to list the database for that instance
Display the database as another combo box
This is the piece of code I have done:-
// dbinstances is a Combo box (Eclipse SWT widget)
this.dbInstances.addSelectionListener(new SelectionListener() {
#Override
public void widgetSelected(SelectionEvent arg0) {
// get selected instance name
String instance = dbInstances.getText();
// command invokes db2 command window, sets current instance and issues list db command
String command = "db2cmd /c \"set DB2INSTANCE="+instance+" & db2 list db directory\"";
// execute command and read output
try{
Process p = Runtime.getRuntime().exec(command);
BufferedReader br= new BufferedReader(new InputStreamReader(p.getInputStream()));
String op = null;
while((op=br.readLine())!=null){
System.out.println(op);
}
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
public void widgetDefaultSelected(SelectionEvent arg0) {}
});
The problem is that the command executes, I am unable to retrieve the output. The window just opens and closes.
One solution I tried was to redirect the output to a temporary file and read it. It works, but is quite inefficient, since this piece of code runs each time the user selects an instance.
I am running DB2 9.7 Enterprise edition on Windows XP SP3 machine.
Any thoughts on how to retrieve the output in the Java program?
Thanks a lot in advance.

You can also use the DB2 API via JNI in order to retrieve the database list directory. You have to start the scan, get the entries, and then close the scan.
By doing this, you can control the db list in a better way that parsing an output that could variate by many reasons (HADR, the authentication mechanism, local or remote, with or without alias, ip address or server name, service name or port number, in linux (home dir) or in Windows (drive letter), and other things)
The DB2 API is the same in all platforms, so it is almost platform independent, you just have to know which library load (.so or .dll), but the rest is the same.
For more information take a look at:
db2DbDirOpenScan http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.api.doc/doc/r0001509.html
db2DbDirGetNextEntry http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.api.doc/doc/r0001492.html
db2DbDirCloseScan http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.api.doc/doc/r0001437.html

Ok, figured this one out. The required solution is to add /w and /i switches to the command :-
// command invokes db2 command window, sets current instance and issues list db command
String command = "db2cmd /c /w /i \"set DB2INSTANCE="+instance+" & db2 list db directory\"";
According to IBM developerWorks
// Additional information about db2cmd Options
-c Execute the DB2 command window and terminate.
-w Wait until the DB2 command window terminates.
-i Inherit the environment from the invoking shell.
-t Inherit the title from the invoking shell

Related

Calling ps on Linux from Java

In Java, I start one new Process using Runtime.exec(), and this process in turn spawns several child processes.
I want to be able to kill all the processes, and have previously been trying process.destroy() and process.destroyForcibly() - but the docs say that destroyForcibly() just calls destroy() in the default implementation and destroy() may not kill all subprocesses (I've tried and it clearly doesn't kill the child processes).
I'm now trying a different approach, looking up the PID of the parent process using the method suggested here and then calling ps repeatedly to traverse the PIDs of child processes, then killing them all using kill. (It only needs to run on Linux).
I've managed the first bit - looking up the PID, and am trying the following command to call ps to get the child PIDs:
String command = "/bin/ps --ppid " + pid;
Process process = new ProcessBuilder(command).start();
process.waitFor();
Unfortunately the 2nd line above is throwing an IOException, with the following message: java.io.IOException: Cannot run program "/bin/ps --ppid 21886": error=2, No such file or directory
The command runs fine if I paste it straight into the terminal on Ubuntu 16.04.
Any ideas would be very much appreciated.
Thanks
Calling the command you wish to run this way is always destined to fail.
Since Process does not effectively run a shell session, the command is basically handed over to the underlying OS to run. This means that it'll fail, since the path to t he program to be executed (in this case ps), is not the full one hence the error you're getting.
Also, testing whether your command works using a terminal is not correct. Using a terminal contains the notion of performing an action with an active logged in user with a correct path etc etc. All the above are not the case though when running a command through Process as these are not taken into consideration.
Furthermore, you also need to account for cases where the actual java application could be running under a different user, with a different set of permissions, paths etc.
In order for your to fix this, you can simply do either of the following:
1) Invoke your ps command using the full path to it (still not sure if it would work)
2) Change the way your create the Process object into something like: p = new ProcessBuilder("bash", "-c", command).start();
The second, will effectively run a bash session, passing in the ps command as an argument thus obtaining the desired result.
http://commons.apache.org/proper/commons-exec/tutorial.html
```
String line = "AcroRd32.exe /p /h " + file.getAbsolutePath();
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(cmdLine);
```

Run external app by userinput

So I'm creating a Java program and I want to make it so that you can ask it to open a program.
But, here's the catch, I want the program it opens to be taken from the user input, right now I'm trying to change this
try{Process p = Runtime.getRuntime().exec("notepad.exe");}
catch(Exception e1){}
Into something that opens a program that you asked it to open.
Here's an example of what I want:
User: Can you open chrome?
Program: Of course, here you go!
chrome opens
Could anyone tell me how I would be able to do this?
You can do it in two ways:
1.By Using Runtime:
Runtime.getRuntime().exec(...)
So, for example, on Windows,
Runtime.getRuntime().exec("C:\application.exe -arg1 -arg2");
2.By Using ProcessBuilder:
ProcessBuilder b = new ProcessBuilder("C:\application.exe", "-arg1", "-arg2");
or alternatively
List<String> params = java.util.Arrays.asList("C:\application.exe", "-arg1", "-arg2");
ProcessBuilder b = new ProcessBuilder(params);
or
ProcessBuilder b = new ProcessBuilder("C:\application.exe -arg1 -arg2");
The difference between the two is :
Runtime.getRuntime().exec(...)
takes a single string and passes it directly to a shell or cmd.exe process. The ProcessBuilder constructors, on the other hand, take a varargs array of strings or a List of strings, where each string in the array or list is assumed to be an individual argument.
So,Runtime.getRuntime.exec() will pass the line C:\application.exe -arg1 -arg2 to cmd.exe, which runs a application.exe program with the two given arguments. However, ProcessBuilder method will fail, unless there happens to be a program whose name is application.exe -arg1 -arg2 in C:.
You can try it with like. Pass whole path of where you install chrome.
try{
Process p = Runtime.getRuntime().exec("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe");
}
catch(Exception e1){
}
When using exec, it is essentially the same as if you were using the command line on windows. Open Command Prompt, type open, and see if it gives details as to how it opens files. If not, find the opener. Usually when dealing with command line operations, there are multiple parameters that are required for opening files/applications. An example of this would be for opening the "TextEdit.app" application on a mac.
Process p = Runtime.getRuntime().exec("open -a TextEdit.app");
Terminal(for mac) would open the app using the -a flag, meaning "application." You could open a file doing:
Process p = Runtime.getRuntime().exec("open filename.file_ext -a TextEdit.app");
The second one will tell the computer to find the application named <app_name>.app and open the file filename.file_ext
I know this is not going to work for a windows machine, but it's only to show how to use the command line operations for opening files and applications. It should be similar for windows though.
Hope this helps

how to create backup of postgres database using java

i want to take backup of postgres database using java. I am using following code for this
but this is not working and not generating dump.
String pgDump = "C:\\Program Files\\PostgreSQL\\9.2\\bin\\pg_dump";
String dumpFile = "D:\\test\\"+ tenant.getTenantAsTemplate()+".sql";
String sql = pgDump+" -h localhost -U postgres -P postgres " + tenant.getTenantAsTemplate()+" > "+dumpFile;
Process p = Runtime.getRuntime().exec(sql);
int time = p.waitFor();
System.out.println("time is "+time);
if(time == 0){
System.out.println("backup is created");
}
else{
System.out.println("fail to create backup");
}
Here i am getting time is 1.
This is also operating system dependent and we need also pg_dump. is there any other way to generate backup of database without pg_dump?
please reply soon.
No, there is no way to generate a database backup without pg_dump, using the regular SQL connection. It's a bit of an FAQ, but the people who want the feature never step up to do the work to implement the feature in PostgreSQL.
I guess technically you could use a replication connection to do a physical base backup like pg_basebackup does, but that's not really what you want, requires copying all databases on the machine, and would be a lot of work.
You should use the String[] form of Runtime.exec as I mentioned in a related answer regarding pg_restore.
You must also check the process exit value to see if it terminated successfully or not, and you must be careful to handle, not just swallow, any exceptions thrown.
Your code fails to check the exit value, and I think it's probably generating a malformed command that's failing with a non-zero exit code, probably because you are not correctly quoting the path to pg_dump. To see what's wrong, print the final assembled command line, you'll see something like:
C:\Program Files\PostgreSQL\9.2\bin\pg_dump -h localhost ....
which cmd.exe will split into:
c:\Program
Files\postgresql\9.2\bin\pg_dump
-h
localhost
... etc
See the problem?
Do not just quote the path to pg_dump to work around this. Use the String[] form of exec and you won't have to, plus it'll work correctly for other things like accidental %environmentvars% in paths.

Runtime.getRuntime().exec strange behavior

I am trying to call a perl script from java runtime. It worked fine on my windows7 laptop with the following code,
try {
String cmdString= "c:\\perl64\\bin\\perl.exe c:\\perl64\\eg\\userinput.pl \""+arg1+"\" \""+arg2+"\"";
Process p = Runtime.getRuntime().exec(cmdString);
} catch(IOException e) {
System.out.println(e);
}
The perl script runs and produces what I expect (update database).
When I move the whole thing over to a remote CentOS server, it doesn't work anymore. The script is the same and the java code is,
try {
String cmdString= "/opt/lampp/bin/perl /home/support/scripts/userinput.pl \""+arg1+"\" \""+arg2+"\" > /tmp/userinput.log";
log(cmdString);
Process p = Runtime.getRuntime().exec(cmdString);
} catch(IOException e) {
System.out.println(e);
}
I added redirect to /tmp/userinput.log after I see the script is not working. But there is no log file created at all. I also added log to make sure this part of the java code did get executed, and indeed it did. I also tried to add "/bin/bash " in front of the comString and it didn't make a difference. However, when I run the cmdString directly on the remote server from command line, it works without problem.
Now, when I changed the cmdString to "touch /tmp/userinput.log", it does create the empty log file.
So I know the Runtime.getRuntime().exec(cmdString) command ran, and the cmdString works when entered on command line, and a simple "touch" command would work with this setup. But I am totally lost why the actual cmdString that calls the perl script doesn't work, and there is no message whatsoever to tell me what is wrong.
Can someone please help?
Frist, separate each parameter for the command and use the version of exec which takes a String[] (you won't have to worry about quoting issues). also, shell redirection won't work since java isn't executing a shell.

Command prompt doesn't open with Runtime.getRuntime().exec

I've created a GUI (swing) that executes a batch file that contains a command prompt .exe file execution with specific parameters.
When I run the batch file manually (by double clicking it), everything is as expected.
The problem is: the command prompt window doesn't open to show progress, moreover, it doesn't really start to work (only initiated) until I exit the GUI (forking?). When it starts to work, is works somewhere in the background and seen only in the task manager.
Only a blank command prompt window is opened.
From digging little bit around, I've constructed this command that gives me same result as above:
Runtime.getRuntime().exec("cmd.exe /c start \"Encoding\" cmd.exe /c start md \"" + Gui.outputDirField.getText() + "\\encoderOutput\" & cd \"" + Gui.outputDirField.getText() + "\\encoderOutput\" & \"" + Gui._batFile + "\" & pause");
Could you please assist?
Sorry if it sounds stupid..
this way works for me:
new Thread() {
#Override public void run() {
try {
Runtime.getRuntime().exec("cmd.exe /c start " + Gui._batFile);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}.run();
trashgod may be on to something. We ran into issues with paths with spaces. This is from the release notes for jre 7u21
Changes to Runtime.exec
On Windows platform, the decoding of command strings specified to Runtime.exec(String), Runtime.exec(String,String[]) and Runtime.exec(String,String[],File) methods, has been improved to follow the specification more closely. This may cause problems for applications that are using one or more of these methods with commands that contain spaces in the program name, or are invoking these methods with commands that are not quoted correctly.
For example, Runtime.getRuntime().exec("C:\\My Programs\\foo.exe bar") is an attempt to launch the program "C:\\My" with the arguments "Programs\\foo.exe" and "bar". This command is likely to fail with an exception to indicate "C:\My" cannot be found.
The example Runtime.getRuntime().exec("\"C:\\My Programs\\foo.exe\" bar") is an attempt to launch the program "\"C:\\My". This command will fail with an exception to indicate the program has an embedded quote.
Applications that need to launch programs with spaces in the program name should consider using the variants of Runtime.exec that allow the command and arguments to be specified in an array.
Alternatively, the preferred way to create operating systems processes since JDK 5.0 is using java.lang.ProcessBuilder. The ProcessBuilder class has a much more complete API for setting the environment, working directory and redirecting streams for the process.
Does your bat file requiere user interaction or why are you putting a pause on your command? If so, the Runtime.exec just runs the file with no window, why would you want a Window? >ou can get a Process object as a result from the exec, from this object you can get an InputStream (and if needed, an OutputStream) so you can print your output or interact with the process.

Categories

Resources