I'm using ProcessBuilder to run Postgres SQL scripts and my process seems to hang, because I'm not getting the exit value.
My code has a test method that loads and executes certain SQL files.
I then run some individual queries before executing the script file whose operations I want to test on.
#Test
public void test340() throws Exception {
String filePath = testFilePath; // Script file I want to test
TreeSet<Path> set = getFilePaths();
for (Path file : set) { // Run previous scripts to setup the db
loadFileAndExecuteSQL(file.toString());
}
preCondition340(); // Run some inserts
loadFileAndExecuteSQL(testFilePath); // Now load the script file I need to test
postCondition340(); // Run some other queries to verify resultset
}
public void loadFileAndExecuteSQL(String scriptFilePath) throws Exception {
String command = String.format("psql -v ON_ERROR_STOP=1 --host %s --port %s --dbname %s --file %s",
"localhost", "5432", dbName, scriptFilePath);
List<String> commands = Arrays.asList(command.split("\\s+"));
ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectErrorStream(true);
final Process process = pb.start();
if(!process.waitFor(10000, TimeUnit.MILLISECONDS)) {
process.destroy();
}
System.out.println("Executing command " + command + process.exitValue());
}
The process seems to hang on my second call to loadFileAndExecuteSQL() Could anyone explain why this is happening and suggest how I can make sure this does not happen? Thanks.
Related
Am trying to get a series of commands on git bash one after the other. I can open the terminal through the code but after that wasn't successful with entering anything. For instance this is the code I tried
String [] args = new String[] {"C:\\Program Files\\Git\\git-bash.exe"};
String something="hi how are you doing";
try {
ProcessBuilder p = new ProcessBuilder();
var proc = p.command(args).start();
var w = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
w.write(something);
} catch (IOException ioException){
System.out.println(ioException);
}
Please let know how to be able to do enter a series of commands into git bash through the code.
The problem is that the command git-bash.exe opens the terminal window but the window's input is still the keyboard, so trying to write to the OutputStream that is returned by method getOutputStream(), in class Process does nothing. Refer to this question.
As an alternative, I suggest using using ProcessBuilder to execute a series of individual git commands. When you do that, your java code gets the command output.
Here is a simple example that displays the git version.
import java.io.IOException;
public class ProcBldT4 {
public static void main(String[] args) {
// C:\Program Files\Git\git-bash.exe
// C:\Program Files\Git\cmd\git.exe
ProcessBuilder pb = new ProcessBuilder("C:\\Program Files\\Git\\cmd\\git.exe", "--version");
pb.inheritIO();
try {
Process proc = pb.start();
int exitStatus = proc.waitFor();
System.out.println(exitStatus);
}
catch (IOException | InterruptedException x) {
x.printStackTrace();
}
}
}
When you run the above code, the git version details will be written to System.out.
Also, if the git command fails, the error details are written to System.err.
You need to repeat the code above for each, individual git command that you need to issue.
I am trying to execute my batch file in java with the following code
String Extraction="cmd.exe /c start C:\\task\\Extracting.bat ";
Runtime.getRuntime().exec(Extraction);
System.out.println("Extracted...");
Here, I want to execute the print statement after execution of the batch file.
But if run the above code, first it opens the command prompt and runs the batch file, and it suddenly execute the print statement before batch file runs. help me to solve this problem.
One more thing that is worth a try is the following. It waits for execution
String Extraction="cmd.exe /c start C:\\task\\Extracting.bat ";
//Runtime.getRuntime().exec(Extraction);
final Process p = new ProcessBuilder("cmd.exe", "/c", "start /WAIT C:\\task\\Extracting.bat").redirectErrorStream(true).start();
p.waitFor();
System.out.println("Job done!!");
To run that command from a Java application using my new code, we'd first build and then exec the command like this:
// build my command as a list of strings
List<String> command = new ArrayList<String>();
command.add("ls");
command.add("-l");
command.add("/var/tmp");
// execute my command
SystemCommandExecutor commandExecutor = new SystemCommandExecutor(command);
int result = commandExecutor.executeCommand();
// get the output from the command
StringBuilder stdout = commandExecutor.getStandardOutputFromCommand();
StringBuilder stderr = commandExecutor.getStandardErrorFromCommand();
// print the output from the command
System.out.println("STDOUT");
System.out.println(stdout);
System.out.println("STDERR");
System.out.println(stderr);
Resource Link:
Java exec - execute system processes with Java ProcessBuilder and
Process (part 1)
Java exec - execute system processes with Java ProcessBuilder and
Process (part 2)
Retrieving Details About Batch Jobs
When a batch job is submitted, the batch runtime creates an instance of JobExecution to track it. JobExecution has methods to obtain various details such as the job start time, job completion time, job exit status, and so on. To obtain the JobExecution for an execution ID, you can use the JobOperator.getJobExecution(executionId) method.
package javax.batch.runtime;
public interface JobExecution {
long getExecutionId();
java.lang.String getJobName();
javax.batch.runtime.BatchStatus getBatchStatus();
java.util.Date getStartTime();
java.util.Date getEndTime();
java.lang.String getExitStatus();
java.util.Date getCreateTime();
java.util.Date getLastUpdatedTime();
java.util.Properties getJobParameters();
}
Role of java here is to invoke cmd then it is upto OS to execute the instructions written in batch file:
You can check below code: Process handle will be returned by exec method.
By using waitFor() it waits for subprocess to finish and then returns exit code.
It will only return 1 when there is problem in path, otherwise 0 for success.
public class TestMe2 {
public static void main(String[] args) {
Process p=null;
String Extraction="cmd.exe /c start C:\\hello.bat ";
try {
p=Runtime.getRuntime().exec(Extraction);
System.out.println(p.waitFor());
} catch (Exception er) {
er.printStackTrace();
}finally{
}
}
}
I am trying to backup MySQL DB using ProcessBuilder in Java but, I get this error.
"!Cannot run program "C:\Program Files\MySQL\MySQL Server 5.5\bin": CreateProcess error=5, Access is denied".
Here is my Code.
public static String backupDb() {
String resp=null;
try {
System.out.println("Started........");
ProcessBuilder builder = new ProcessBuilder("C:\\Program Files\\MySQL\\MySQL Server 5.5\\bin", "mysqldump -u root -pmypass mydb> c:\\backup\\mybackup.sql");
builder.redirectErrorStream(true);
Process p = builder.start();
} catch(Exception e) {
resp="!"+e.getMessage();
}
return resp;
}
Where could I be going wrong?
There are a few things you have to do for this to work:
open a terminal/console to run the mysql dump command in, else the redirection operator(>) won't work.
check that required folders from file path exist. For instance, if you want to backup your database in C:\\foo\bar\foobar\backup.sql but one of the C:\\foo, C:\\foo\\bar, C:\\foo\\bar\\foobar folders doesn't exist, you'll get an error
Adjust the path to mysqldump so that folder names containing white spaces are wrapped in " ", else you'll get awkward errors, such as : 'C:\Program' is not recognized as an internal or external command
read the error stream in case of error, else your process will hang. A return value of 0 indicates success.
Here is a tested version including all the things above. I'm passing the filepath as a parameter, because it's more flexible this way.
public static void backupDb(final String mysqlDumpFilePath)
throws IOException, InterruptedException {
String folderPath = mysqlDumpFilePath.substring(0, mysqlDumpFilePath.lastIndexOf("\\"));
File folder = new File(folderPath);
if (!folder.exists()) {
folder.mkdirs(); // 2
}
File f = new File(mysqlDumpFilePath);
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "C:\\\"Program Files\"\\MySQL\\\"MySQL Server 5.5\"\\bin\\mysqldump -u root -pmypass mydb > "
+ f.getAbsolutePath()); //1 & 3
Process exec = builder.start();
int retCode = exec.waitFor();
if (retCode != 0) { //4
// something went wrong
InputStream errorStream = exec.getErrorStream();
byte[] buffer = new byte[errorStream.available()];
errorStream.read(buffer);
System.out.println(new String(buffer));
}
}
I have a perl script that i'm trying to execute through shell. The normal UNIX shell invocation is do is: /home/projects/bumble/script.pl --input /home/input/input.txt > /home/output/output.txt.
To do this in Java I wrote a function:
public void runCommand(String command, File directory) {
final ProcessBuilder pb = new ProcessBuilder(command);
pb.directory(directory);
final Process process = pb.start();
if(process.waitFor() != 0) {
throw new RuntimeException("ERROR");
}
}
I call this:
String command = "/home/projects/bumble/script.pl --input /home/input/input.txt > /home/output/output.txt";
File directory = new File("/home/projects/bumble");
runCommand(command,directory);
The exception I get is:
java.io.IOException: ... Cannot run program error=2, No such file or directory
I notice here: java.io.IOException: Cannot run program error=2, No such file or directory, implies that running programs given a full input with > into a completely different directory would fail. If I just run the command /home/projects/bumble/script.pl --input /home/input/input.txt, also fails with the same error. I run it directly through shell, it does work. Is there something I am missing or doing incorrectly?
Runtime.exec() traps: http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=3
2 problems with the code:
Command should be broken down into a String[] such as:
String[] command = {"perl", "/home/projects/bumble/script.pl", "--input", "/home/input/input.txt"}
Output needs to be handled seperately without the redirect ">". To do this, ProcessBuilder has Redirect. http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.Redirect.html
Programmatically the function is:
public static void runCommand(final String[] command, final File directory, final File output) throws IOException, InteruptException {
final ProcessBuilder pb = new ProcessBuiler(command);
pb.redirectErrorStream(true); //optional; easier for this case to only handle one stream
pb.redirectOutput(Redirect.to(output));
final Process p = pb.start();
if(p.waitFor != 0) {
//throw an exception / return error message
}
}
I have written a shell script for automatic
1) start of hadoop services (namenode,datanode,jobtracker,tasktracker,secondary namenode),
2) dropping all tables from hive
3) again importing all tables in hive from SQL SERVER
And I am calling this shel script from java. Below is the code of Shell Script and Java Code
Shell Script:
export HADOOP_HOME=/home/hadoop/hadoop-0.20.2-cdh3u2/
export HIVE_HOME=/home/hadoop/hive-0.7.1/
export SQOOP_HOME=/home/hadoop/sqoop-1.3.0-cdh3u1/
export MSSQL_CONNECTOR_HOME=/home/hadoop/sqoop-sqlserver-1.0
export HBASE_HOME=/home/hadoop/hbase-0.90.1-cdh3u0
export ZOOKEEPER_HOME=/home/hadoop/zookeeper-3.3.1+10
export SQOOP_CONF_DIR=/home/hadoop/sqoop-1.3.0-cdh3u1/conf/
/home/hadoop/hadoop-0.20.2-cdh3u2/bin/hadoop/start-all.sh
/home/hadoop/hadoop-0.20.2-cdh3u2/bin/hadoop -rmr /user/hadoop/*
/home/hadoop/hive-0.7.1/bin/hive -e 'show tables' > TablesToDelete.txt
while read line1
do
echo 'drop table '$line1
/home/hadoop/hive-0.7.1/bin/hive -e 'drop table '$line1
done < TablesToDelete.txt
while read line
do
echo $line" ------------------------------"
/home/hadoop/sqoop-1.3.0-cdh3u1/bin/sqoop-import --connect 'jdbc:sqlserver://192.168.1.1;username=abcd;password=12345;database=HadoopTest' --table line --hive-table $line --create-hive-table --hive-import -m 1 --hive-drop-import-delims --hive-home /home/hadoop/hive-0.7.1 --verbose
done < /home/hadoop/sqoop-1.3.0-cdh3u1/bin/tables.txt
Java Code:
public class ImportTables
{
public static void main(String arsg[])
{
PrintWriter pw=null;
try
{
Formatter formatter = new Formatter();
String LogFile = "Log-"+ formatter.format("%1$tm%1$td-%1$tH%1$tM%1$tS", new Date());
File f=new File("/home/hadoop/"+LogFile);
FileWriter fw1=null;
pw=new PrintWriter(f);
String cmd = "/home/hadoop/sqoop-1.3.0-cdh3u1/bin/TablesToImport.sh"; // this is the command to execute in the Unix shell
// create a process for the shell
ProcessBuilder pb = new ProcessBuilder("bash", "-c", cmd);
pb.redirectErrorStream(true); // use this to capture messages sent to stderr
Process shell = pb.start();
InputStream shellIn = shell.getInputStream(); // this captures the output from the command
int shellExitStatus = shell.waitFor();
// wait for the shell to finish and get the return code
// at this point you can process the output issued by the command
// for instance, this reads the output and writes it to System.out:
int c;
while ((c = shellIn.read()) != -1)
{
System.out.write(c);
}
// close the stream
shellIn.close();
}
catch(Exception e)
{
e.printStackTrace();
e.printStackTrace(pw);
pw.flush();
System.exit(1);
}
}
}
But as I run the program I see nothiing on the console, and program remains in running mode.
And If I put the following code ion shell script:
/home/hadoop/hive-0.7.1/bin/hive -e 'show tables' > TablesToDelete.txt
while read line1
do
echo 'drop table '$line1
/home/hadoop/hive-0.7.1/bin/hive -e 'drop table '$line1
done < TablesToDelete.txt
Then the output come as:
Cannot find hadoop installation: $HADOOP_HOME must be set or hadoop must be in the path
What is the problem in my program/script? Where and How to set HADOOP_HOME and all that path in my script?
The call to waitFor is a blocking call, just as the name implies. It halts further execution until the process is done. But since your code is also the sink for the process's stdout, the whole thing blocks. Just move the waitFor to after you've processed the script's output.