I want to create a backup of my database using pg_dump in java. The creation of backup works fine, but it doesn't start before the program exits.
Is there any way to start the backup instantly?
public static void backupDb() throws IOException, InterruptedException {
String path = "C:\\HACENE\\test.backup";
Runtime r = Runtime.getRuntime();
//PostgreSQL variables
String host = "localhost";
String user = "postgres";
String dbase = "gtr_bd";
String password = "postgres";
Process p;
ProcessBuilder pb;
r = Runtime.getRuntime();
pb = new ProcessBuilder("C:\\Program Files\\PostgreSQL\\9.3\\bin\\pg_dump", "-v", "-h", host, "-f", path, "-U", user, dbase);
pb.environment().put("PGPASSWORD", password);
pb.redirectErrorStream(true);
p = pb.start();
System.out.println("end of backup");
}
You should check the state of the Process instance returned from ProcessBuilder.start(). As already mentioned in the comments you can use the Process.waitFor() method to wait for the process to finish. Furthermore you should consider inspecting the exit value of the started process to determine if your backup was successful or not.
This is what I did in a project of mine:
private void validateExitValue(final Process aProcess, final String aCommand,
final String aResult) throws IllegalStateException {
do {
try {
if (aProcess.waitFor() != 0) {
final String errorMessage = String.format("Command '%s' terminated with exit status '%s': %s",
aCommand, aProcess.exitValue(), aResult);
throw new IllegalStateException(errorMessage);
}
break;
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
}
} while (true);
}
This method will wait for the process to finish and throw an IllegalStateException, if the process finished with an exit code other than 0.
The observation that the backup process currently is started just as your Java program terminates is just by coincidence I suspect, as starting the backup process is very likely the last action that is performed by your Java program. Starting the external process will take some time and your program continues and terminates, that is it looks like the the process is being started at termination of the Java program.
// Comment -> p = pb.start();
// add this at the end:
final Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
// because you put "-v" in your command. Another way is to remove "-v" from your command
-v Specifies verbose mode. This will cause pg_dump to output detailed object comments and start/stop times to the dump file, and progress messages to standard error. From this LINK
If you execute this command in cmd this work fine:
"C:\Program Files\PostgreSQL\9.3\bin\pg_dump.exe" -U postgres -h localhost -p 5432 database_name > "C:\Test\test.buckup"
So you can put this lines in a .bat file like this:
#echo off
cd "C:\Program Files\PostgreSQL\9.3\bin\"
pg_dump.exe -U postgres -h localhost -p 5432 bd_suivi > "C:\Test\test.buckup"
exit
And execute this file.bat with java, like this:
public static void main(String[] args) {
try {
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "start script.bat");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) {
break;
}
System.out.println(line);
}
System.out.println("I finished the creation of the buckup!");
} catch (Exception e) {
System.out.println("Exception = " + e);
}
}
good luck.
Related
I want to execute a program through the command line similar to java -jar xxx.jar
then get the process ID of the program
judge whether the process is alive or not by the process ID later.
//start a process
String command = "...";
ProcessBuilder pb = new ProcessBuilder(command);
Process process = pb.start();
//get the pid of process
if (System.getProperty("os.name").toLowerCase().contains("mac")) {
Class<?> clazz = Class.forName("java.lang.UNIXProcess");
field = clazz.getDeclaredField("pid");
ReflectionUtils.makeAccessible(field);
pid = (Integer) field.get(process);
}
Then, i want to determine if this process is alive,i tried like:
// judge the process is alive or not. By pid.
if (System.getProperty(Constants.SYSTEM_NAME).toLowerCase().contains("linux") || System.getProperty(Constants.SYSTEM_NAME).toLowerCase().contains("mac")) {
process = RuntimeUtil.exec(BIN_BASH + " -c" + " ps -elf | grep " + pid);
}
if(process != null){
String line;
try(InputStream in = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in,StandardCharsets.UTF_8))){
while((line = br.readLine()) != null){
if(line.contains(pid)){
// i can't see the pid of my process (always)
return true;
}
}
} catch (IOException e) {
//exception handle
}
}
Since Java 9 there is standard library to get all alive process. With this you can simply find if process with pid is alive.
private boolean checkIsProcessAlive(Long pid)
{
return ProcessHandle.allProcesses()
.map(ProcessHandle::pid)
.anyMatch(p -> p.equals(pid));
}
But there is one more way to reach this. When you create process object with Process process = pb.start(); you can check if process is alive with process.isAlive(); method.
I would like to run a hidden script file that resides in the current location using process builder. with the following code
// System.out.println("line"+reader.readLine());
ProcessBuilder builder = new ProcessBuilder(shfile.getAbsolutePath());
builder.redirectErrorStream(true);
Process process = builder.start();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String output = null;
System.out.println("out"); //===printing this
while (null != (output = br.readLine()))
{
System.out.println("in"); //not printing this
System.out.println(">>"+output);
}
int rs = process.waitFor();
but it hangs in the br.readline()..
but when I run the same script file using the following command in terminal
sh .script.sh
it executes and gives me the expected results
I looked into all the loops in the forum everyone asks to handle input stream and error stream in threads or do a redirect error stream. I have added a redirect error stream but still it hangs.
when i press ctrl+c it prints the initial lines of the output and exits.
Content of my script file
#!/bin/sh
cd /home/ats/cloudripper/lke_factory_asb_v2/lk_assets_factory_release/
sh ./LKE_run_Diablo.sh 0a0e0c3dc893
So how to handle this situation.
Process builder have special API to redirect child process input, output and error streams. See documentation
If you need both child and parent process to use same console you should use INHERIT mode redirection. An example:
public class ChildProcessOutputProxy {
public static void main(String[] args) {
ProcessBuilder builder = new ProcessBuilder("whoami");
builder.redirectOutput(Redirect.INHERIT);
builder.redirectErrorStream(true);
try {
var child = builder.start();
child.waitFor();
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
I already create the .sh file, and the inside is:
sudo iptables --flush
sudo iptables -A INPUT -m mac --mac-source 00:00:00:00:00:00 -j DROP
It works normally when I run it on the terminal, but when I use processbuilder, it didn't do anything. No error, but didn't happen anything, this is the code on my java:
Process pb = new ProcessBuilder("/bin/bash","/my/file.sh").start();
I already looking for the answer, but I still failed to run the .sh file, even I do the same thing with people that already done it.
Sorry if this is a bad question, thank you.
Are you sure that the bash is not run? Do you checked the Process object returned by the startmethod? You can get the output value, the output stream, etc. from this objects.
Check your streams and exitvalue for errors... sudo is probably the problem here.
Not necessarily the best code but it gets the job done. Executes a process, takes the process.streams and prints them to System.out. Might helpt to find out what the issue actually is atlest.
ProcessBuilder pb = new ProcessBuilder(args);
pb.redirectErrorStream(true);
final Process proc = pb.start();
final StringBuilder builder = new StringBuilder("Process output");
final Thread logThread = new Thread() {
#Override
public void run() {
InputStream is = proc.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
try {
String line;
do {
line = reader.readLine();
builder.append("");
builder.append(line == null ? "" : line);
builder.append("<br/>");
} while(line != null);
} catch (IOException e) {
builder.append("Exception! ").append(e.getMessage());
} finally {
try {
reader.close();
} catch (IOException e) {
builder.append("Exception! ").append(e.getMessage());
}
}
}
};
logThread.start();
int retVal = proc.waitFor();
System.out.println(builder.toString());
From Java API Runtime : http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html
// Java runtime
Runtime runtime = Runtime.getRuntime();
// Command
String[] command = {"/bin/bash", "/my/file.sh"};
// Process
Process process = runtime.exec(command);
Also you should be careful with sudo commands that may ask for root password.
The program I'm working on uses ADB (Android Debug Bridge) to send files to my phone:
for (String s : files)
String cmd = "adb -s 0123456789ABCDEF push " + s + " /mnt/sdcard/" + s;
try {
InputStream is = Runtime.getRuntime().exec(cmd).getInputStream();
while (is.read() != -1) {}
} catch (IOException e) {
e.printStackTrace();
}
I want the program to wait until ADB finished the transmission, but ADB runs as a daemon and therefore never finishes. But the program continues immideately and somehow the files aren't sent to my phone (no exceptions in log). When I run the command from console, it's working without problems.
What am I doing wrong? How do I send files via ADB correctly?
NOTE: the is.read() == -1 won't work, because the ADB daemon writes all output to the system standard output. I've tried forwarding it into a textfile. It stayed empty and the output was still written to the terminal instead
EDIT: Reading the ErrorStream of the ADB process returned the adb help for each adb push-command. Again: The exact commands (copied from Eclipse console) work in a terminal
EDIT 2: Using a ProcessBuilder instead of RUntime.getRuntime.exec() resulted in the following error:
java.io.IOException: Cannot run program "adb -s 0123456789ABCDEF push "inputfile "outputfile""": error=2, File or directory not found
at the ProcessBuilder's start()-method
The same happens when using an absolute path for ADB (/usr/bin/adb). The inputfile and outputfile Strings are also absolute paths, like /home/sebastian/testfile and definitely exist. When running the commands from terminal (string "cmd" printed, copy&paste), evreything still works fine.
I finally got it working:
ProcessBuilder pb = new ProcessBuilder("adb", "-s", "0123456789ABCDEF", "push", inputfile, outputfile);
Process pc = pb.start();
pc.waitFor();
System.out.println("Done");
I don't know what problems ProcessBuilder has with spaces in a string, but finally, it's working...
I've solved in this way:
public class Utils {
private static final String[] WIN_RUNTIME = { "cmd.exe", "/C" };
private static final String[] OS_LINUX_RUNTIME = { "/bin/bash", "-l", "-c" };
private Utils() {
}
private static <T> T[] concat(T[] first, T[] second) {
T[] result = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
public static List<String> runProcess(boolean isWin, String... command) {
System.out.print("command to run: ");
for (String s : command) {
System.out.print(s);
}
System.out.print("\n");
String[] allCommand = null;
try {
if (isWin) {
allCommand = concat(WIN_RUNTIME, command);
} else {
allCommand = concat(OS_LINUX_RUNTIME, command);
}
ProcessBuilder pb = new ProcessBuilder(allCommand);
pb.redirectErrorStream(true);
Process p = pb.start();
p.waitFor();
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String _temp = null;
List<String> line = new ArrayList<String>();
while ((_temp = in.readLine()) != null) {
System.out.println("temp line: " + _temp);
line.add(_temp);
}
System.out.println("result after command: " + line);
return line;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
If you don't need env variables in your .bash_profile cut "-l" parameter.
I have a Mac but it should work on Linux also.
public static void adbpush() {
System.out.println("adb push....");
String[] aCommand = new String[] { adbPath, "push", inputFile(String),OutputDirectory };
try {
// Process process = new ProcessBuilder(aCommand).start();
Process process = Runtime.getRuntime().exec(aCommand);
process.waitFor(3, TimeUnit.SECONDS);
System.out.println("file pushed");
} catch (Exception e) {
e.printStackTrace();
}
}
It will be better to give full path for ADB execution: like this $ANDROID_HOME/platform-tools/adb devices
This is the full code you can use:
String cmd = "$ANDROID_HOME/platform-tools/adb devices";
ProcessBuilder processBuilder = new ProcessBuilder();
if (Config.osName.contains("Windows"))
processBuilder.command("cmd.exe", "/c", cmd);
else
processBuilder.command("bash", "-c", cmd);
Process process = processBuilder.start();
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
string cmd = "/system/bin/input keyevent 23\n";
os.writeBytes(cmd);
the phone must be rooted. here I have executed adb command "input keyevent 23". remember when you execute adb command through su you does not need to add "adb shell input keyevent 23"
I have a simple GUI program where one of the features is to ping a destination from a file. I have the ping running fine when using normal ping x.x.x.x however when running this with the -t command i have noticed that even after closing the command window ping.exe is still showing in the process list. I know the process can be ended using ctrl+c but is there a different way to get the process to end when the user closes the cmd window?
i am currently using this code:
try {
ipPing = VNC.getIp().concat(ext);
String command = "ping " + ipPing;
Runtime rt = Runtime.getRuntime();
rt.exec(command);
rt.exec(new String[]{"cmd.exe", "/C", "\"start;" + command + "\""});
} catch (IOException e) {
}
any advice and tips would be greatly appreciated
I'm not sure will it work, but you can try Process.destroy(). Something like this:
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/C", "\"start;" + command + "\"");
Process p = pb.start();
//...
p.destroy();
Also, don't write empty catch blocks:
} catch (IOException e) {
}
because if an exception gets thrown it'll be hard to notice. Unless of course, you know that you can ignore the exception.
UPDATE:
proof of concept for linux os:
public static void main(String[] args) throws IOException {
ProcessBuilder pb = new ProcessBuilder("ping","localhost");
pb.redirectErrorStream(true);
Process p = pb.start();
InputStreamReader isr = new InputStreamReader(p.getInputStream());
int ch,count = 0;
StringBuffer sb = new StringBuffer();
while((ch =isr.read()) > -1) {
sb.append((char)ch);
if ((char)ch == '\n') {
System.out.println( sb.toString());
sb = new StringBuffer();
}
if (count++ == 2) {
System.out.println("destroying process");
p.destroy();
}
}
}
outputs:
destroying process
PING localhost (127.0.0.1) 56(84) bytes of data.
Exception in thread "main" java.io.IOException: Stream closed
64 bytes from localhost (127.0.0.1): icmp_req=1 ttl=64 time=0.031 ms
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:145)
at java.io.BufferedInputStream.read(BufferedInputStream.java:308)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:107)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:93)
at java.io.InputStreamReader.read(InputStreamReader.java:151)
at com.infobip.rhino.Killer.main(Killer.java:24)
Java Result: 1
the lines are messed up because the error stream is redirected to output stream