Running a cmd from java and add sql plus commands - java

I am working at an application with 2 button Run and Commit.
When i press Run, my application run a script in sql plus. The idea is that i want to remain in sql plus and make commit when i press the Commit button. Also i want to see the output of every command. The things are working fine till i press commit. The output is not showing..
My Run button action:
package pachet1;
import java.util.Scanner;
import javafx.scene.control.TextArea;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbFile;
import java.io.*;
import java.net.MalformedURLException;
import java.nio.file.Files;
public class MyExec {
public static ProcessBuilder builder;
public static Process p;
public static BufferedReader bri;
public static BufferedReader bre;
public static BufferedWriter p_stdin;
public static void executeScript(String scriptName, String alias, String path, TextArea txtArea) throws IOException
{
NtlmPasswordAuthentication userCred = new NtlmPasswordAuthentication("domain",
"username", "password");
SmbFile smbFile=new SmbFile("path" + scriptName, userCred);
File file = new File("D://" + scriptName);
try (InputStream in = smbFile.getInputStream()) {
Files.copy(smbFile.getInputStream(), file.toPath());
}
//init shell
builder = new ProcessBuilder( "cmd" );
builder.redirectErrorStream(true);
try {
p = builder.start();
}
catch (IOException e) {
//System.out.println(e);
}
//get stdin of shell
p_stdin =
new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
// execute the desired command (here: ls) n times
int n=1;
try {
//single execution
p_stdin.write("sqlplus sys/sys#" + alias +" as sysdba");
p_stdin.newLine();
p_stdin.flush();
p_stdin.write("#"+file.toPath());
p_stdin.newLine();
p_stdin.flush();
// p_stdin.write("commit;");
// p_stdin.newLine();
// p_stdin.flush();
}
catch (IOException e) {
//System.out.println(e);
}
// finally close the shell by execution exit command
try {
p_stdin.write("");
p_stdin.newLine();
p_stdin.flush();
}
catch (IOException e) {
System.out.println(e);
}
// write stdout of shell (=output of all commands)
String line;
bri = new BufferedReader
(new InputStreamReader(p.getInputStream()));
bre = new BufferedReader
(new InputStreamReader(p.getErrorStream()));
while ((line = bri.readLine()) != null) {
txtArea.appendText(line + "\n");
System.out.println(line + "\n");
}
//bri.close();
while ((line = bre.readLine()) != null) {
txtArea.appendText(line + "\n");
System.out.println(line + "\n");
}
//bre.close();
System.out.println("Done.");
}
}
My commit button action:
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
MyExec.p_stdin.write("commit");
MyExec.p_stdin.newLine();
MyExec.p_stdin.flush();
MyExec.p_stdin.write("exit");
MyExec.p_stdin.newLine();
MyExec.p_stdin.flush();
//txtArea.appendText("Commit complete.");
String line;
MyExec.bri = new BufferedReader
(new InputStreamReader(MyExec.p.getInputStream()));
MyExec.bre = new BufferedReader
(new InputStreamReader(MyExec.p.getErrorStream()));
while ((line = MyExec.bri.readLine()) != null) {
txtArea.appendText(line + "\n");
System.out.println(line + "\n");
}
MyExec.bri.close();
while ((line = MyExec.bre.readLine()) != null) {
txtArea.appendText(line + "\n");
System.out.println(line + "\n");
}
MyExec.bri.close();
System.out.println("Done.");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
public void commit(ActionEvent e)
{
t1.start();
}
So i need in that thread to get the process output from run button and continues to display it, but it's not working..

Related

Unable to run batch script successfully from Java

The following batch script that works fine if I run it in a batch file (.bat). It gets all the files on the SFTP server and downloads to the local folder.
However, if I run this from the Java code, it gets only 4 files. Why is that it stops after it gets the 4 files?
Batch script:
winscp.com /log=C:\winscp\logs\winscp_detailed.log /xmllog=C:\winscp\logs\winscp.log /command ^
"open sftp://root:password#xx.xxx.xx.xx/ -privatekey=""C:\winscp\key.ppk"" -hostkey=""ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"" -passphrase=""password""" ^
"get /home/SFTP/* C:\LocalFolder1\" ^
"exit"
Java Code that executes the above command:
public HashMap runExternalProgram_Windows(String Command) {
String line;
InputStream stderr = null;
InputStream stdout = null;
HashMap _m = new HashMap();
try {
Process process = Runtime.getRuntime ().exec (Command);
Worker worker = new Worker(process);
worker.start();
try {
worker.join(30000);
if (worker.exit == null) {
throw new Exception();
}
} catch(Exception ex) {
_m.put("LOG_ERROR_EXTERNAL", "30 second time out...check connection");
ex.printStackTrace();
return _m;
} finally {
process.destroy();
}
stderr = process.getErrorStream ();
stdout = process.getInputStream ();
String _log_output = null;
// clean up if any output in stdout
BufferedReader brCleanUp = new BufferedReader (new InputStreamReader (stdout));
while ((line = brCleanUp.readLine ()) != null) {
if (_log_output==null) {
_log_output = line + "\n";
} else {
_log_output = _log_output + line + "\n";
}
}
brCleanUp.close();
_m.put("LOG_OUTPUT", _log_output);
String _log_error = null;
// clean up if any output in stderr
brCleanUp=new BufferedReader (new InputStreamReader (stderr));
while ((line = brCleanUp.readLine ()) != null) {
if (_log_error==null) {
_log_error = line + "\n";
} else {
_log_error = _log_error + line + "\n";
}
}
brCleanUp.close();
_m.put("LOG_ERROR_EXTERNAL", _log_error);
} catch (Exception e) {
//e.printStackTrace();
}
return _m;
}
private static class Worker extends Thread {
private final Process process;
private Integer exit;
private Worker(Process process) {
this.process = process;
}
public void run() {
try {
exit = new Integer(process.waitFor());
} catch (InterruptedException ignore) {
return;
}
}
}

Java program hangs when trying to invoke powershell script

I'm building a GUI with NetBeans, and one of the buttons in the GUI requires the use of a powershell script. I'm trying to get the script's output and put it into a JTextArea within the GUI. Here is what I have so far. I did a bit of debugging, and it seems to hang inside the while loop, but I'm confused as to why it's doing so.
private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("cmd powershell C:/hello1.ps1");
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null) {
outputTextArea.setText(line);
}
reader.close();
proc.getOutputStream().close();
} catch (IOException ex) {
Logger.getLogger(BatchFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
And here is a simple powershell script I'm trying to get it to work with.
#Filename: hello1.ps1
Write-Host "Hello World!"
#End of Script
I did some researched, and I noticed that it was hanging for other people to, but only because they forgot to close the processes output stream.
I was having the same issue. I moved the proc.getOutputStream().close() before the while loop and everything worked
private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
String allOutput = "";
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("cmd /c powershell C:/hello1.ps1");
BufferedReader errorReader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
BufferedReader outReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
while ((line = errorReader.readLine()) != null) {
allOutput += "\n" + line;
}
while ((line = outReader.readLine()) != null) {
allOutput += "\n" + line;
}
int retVal = proc.waitFor();
} catch (IOException ex) {
Logger.getLogger(BatchFrame.class.getName()).log(Level.SEVERE, null, ex);
}
outputTextArea.setText(allOutput);
}
Form the command line properly with CMD.EXE /c
Check the ErrorStream
Use Process.waitFor() read the java-docs for the Process class.
No need to close the OutputStream since you never use it and the program shouldn't expect user input (java switching the names of input and output is annoying)
NOTE the code above isn't tested, so there may be syntax errors etc etc.
Here is my tested code, note the choice to "hack" or close STDIN when done.
package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Test
{
private static boolean hack=false;
public static void main(String[] args) throws IOException
{
Runtime rt = Runtime.getRuntime();
String cmd[];
if (hack)
cmd=new String[]{"cmd","/c","C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\powershell.exe","-File","c:\\cygwin\\home\\jpyeron\\test.ps1", "<NUL"};
else
cmd=new String[]{"C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\powershell.exe","-File","c:\\cygwin\\home\\jpyeron\\test.ps1"};
final Process p = rt.exec(cmd);
Thread stdout = new Thread()
{
public void run()
{
InputStream out = p.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(out));
String line = null;
try
{
while ((line = in.readLine()) != null)
{
System.out.println(line);
}
}
catch (IOException e)
{
e.printStackTrace();
}
};
};
stdout.start();
Thread stderr = new Thread()
{
public void run()
{
InputStream err = p.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(err));
String line = null;
try
{
while ((line = in.readLine()) != null)
{
System.out.println(line);
}
}
catch (IOException e)
{
e.printStackTrace();
}
};
};
stderr.start();
if (hack)
;
else
p.getOutputStream().close();
}
}
This helped me: Do not read the InputStream if there are no errors.
e.g.
private void takeAction () throws IOException, InterruptedException
{
String action = getAction (); // A powershell-Command
Process p = Runtime.getRuntime ().exec ( action );
InputStream is = p.getErrorStream ();
if ( 0 < is.available () )
{
BufferedReader br = new BufferedReader (
new InputStreamReader ( is ) );
String err = br.readLine ();
while ( null != err )
{
System.out.println ( "takeAction() " + err );
err = br.readLine ();
}
p.getOutputStream ().close ();
}
}

Runtime.exec never returns when reading system.in

Here is my sample code, I want to handle the command from standard input while running a new sub process. However, the exec method never returns if I read the system.in. The command in the exec() is very simple and has nothing to do with the stdin.
I'm wondering about is there any way to solve this? How can I start a new sub process while start another thread reading stdin?
public static void main(String[] args){
new Thread(new Runnable(){
public void run(){
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
try{
while((command = reader.readLine()) != null){
System.out.println("Command Received:" + command);
}
}catch(Exception ex){
ex.printStackTrace();
//failed to listening command
}
}
}).start();
Process process = null;
try {
process = Runtime.getRuntime().exec("java -cp C:/agenttest Test");
System.out.println("never returns");
process.waitFor();
} catch (IOException e) {
throw new RuntimeException( e );
} catch (InterruptedException e) {
throw new RuntimeException( e );
}
}
The Test class is very simple, here is the Test.java
public static void main(String[] args){
System.out.println("Standard out");
System.out.println("Standard out");
System.err.println("Standard err");
System.out.println("Standard out");
try{
Thread.sleep(10000);
}catch(InterruptedException ex){}
}
The problem could be that you're not handling the error stream and input stream and are overrunning the platform's buffers. Try handling that output as per the famous article, When Runtime.exec() won't.
For example:
import java.io.*;
public class TestMain {
private static final String JAVA_CMD = "java";
private static final String CP = "-cp";
// *** your CLASS_PATH and PROG Strings will of course be different ***
private static final String CLASS_PATH = "C:/Users/hovercraft/Documents/workspace/Yr 2012A/bin";
private static final String PROG = "yr12.m07.b.Test2";
private static final String[] CMD_ARRAY = { JAVA_CMD, CP, CLASS_PATH, PROG };
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String command = null;
try {
while ((command = reader.readLine()) != null) {
System.out.println("Command Received:" + command);
}
} catch (Exception ex) {
ex.printStackTrace();
// failed to listening command
}
}
}).start();
Process process = null;
try {
ProcessBuilder processBuilder = new ProcessBuilder(CMD_ARRAY);
process = processBuilder.start();
InputStream inputStream = process.getInputStream();
setUpStreamGobbler(inputStream, System.out);
InputStream errorStream = process.getErrorStream();
setUpStreamGobbler(errorStream, System.err);
System.out.println("never returns");
process.waitFor();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void setUpStreamGobbler(final InputStream is, final PrintStream ps) {
final InputStreamReader streamReader = new InputStreamReader(is);
new Thread(new Runnable() {
public void run() {
BufferedReader br = new BufferedReader(streamReader);
String line = null;
try {
while ((line = br.readLine()) != null) {
ps.println("process stream: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
You should keep reading the input stream, otherwise it will get blocked. It has nothing to do with JVM but the underyling operating system.

Java webpanel commands not saving

I have a java app that gets commands from a webpanel, and when it executes a command, it saves somewhere so that it knows that it has executed already. then when it next executes a command, it checks the list before executing the command, this works fine one a PC, but on a mac, it seems to not work.
it saves the commands, but when it checks for new commands, it executes all previous commands aswell.
n3.data contains:
1,2,3,4,
each command is given an id (in this case 1 2 3 and 4), the app is supposed to check what command ids it has used and then execute if the id is not in the specified file (n3.data)
here is the code.
public void save(int id) {
String osName = System.getProperty("os.name");
if(osName.contains("Windows")){
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(System.getProperty("user.home") + "\\app.data", true));
bw.write(id + ",");
bw.close();
} catch (IOException ex) {
ex.printStackTrace();
}
} else if(osName.contains("Mac")){
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(System.getProperty("user.home") + "/n3.data", true));
bw.write(id + ",");
bw.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public void createNew() {
String osName = System.getProperty("os.name");
File win = new File(System.getProperty("user.home") + "\\app.data");
File mac = new File(System.getProperty("user.home") + "/n3.data");
if(osName.contains("Windows") && !win.exists()){
try {
new File(System.getProperty("user.home") + "\\app.data").createNewFile();
} catch (IOException ex) {
ex.printStackTrace();
}
}else if(osName.contains("Mac") && !mac.exists()){
try {
new File(System.getProperty("user.home") + "/n3.data").createNewFile();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public void saveNew() {
String osName = System.getProperty("os.name");
if(osName.contains("Windows")){
StringBuilder sb = new StringBuilder();
for (int i : processedIds) {
sb.append(i + ",");
}
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(System.getProperty("user.home") + "\\app.data"));
bw.write(sb.toString());
bw.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}else if(osName.contains("Mac")){
StringBuilder sb = new StringBuilder();
for (int i : processedIds) {
sb.append(i + ",");
}
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(System.getProperty("user.home") + "/n3.data"));
bw.write(sb.toString());
bw.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public void loadSave() throws IOException {
String osName = System.getProperty("os.name");
if(osName.contains("Windows")){
File file = new File(System.getProperty("user.home") + "\\app.data");
if (file.exists()) {
BufferedReader br = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
for (String s : sb.toString().split(",")) {
try {
processedIds.add(Integer.parseInt(s));
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
file.createNewFile();
}
}else if(osName.contains("Mac")){
File file = new File(System.getProperty("user.home") + "/n3.data");
if (file.exists()) {
BufferedReader br = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
for (String s : sb.toString().split(",")) {
try {
processedIds.add(Integer.parseInt(s));
} catch (Exception e) {
e.printStackTrace();
}
}
} else if (!file.exists()){
file.createNewFile();
}
}
}
I figured it out, anyone having the same problem, the code doesn't check properly if the file exists or not. just fix that and it should work.

How to destroy a Process in java

I wrote the code below. To run a bat file from Java app, I use a process.exec(). But the bat may hang sometime, so I need to set a timeout for this process. I start a new thread and new a process in the thread, I set a timeout in the thread, and kill the thread when it is timeout. But I found that the process couldn't be destroyed when timeout happens. So I am confused about how to kill the porcess?
The code:
StreamGobbler:
import java.util.*;
import java.io.*;
class StreamGobbler extends Thread
{
InputStream is;
String type;
StreamGobbler(InputStream is, String type)
{
this.is = is;
this.type = type;
}
public void run()
{
try
{
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null)
System.out.println(type + ">" + line);
} catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
Main:
public class test
{
public static void main(String args[]) throws InterruptedException
{
Runnable r = new ShengThread();
Thread sheng = new Thread(r);
sheng.start();
sheng.join(1000);
if (sheng.isAlive()) {
sheng.interrupt();
}
if (sheng.isAlive()) {
System.out.println("It is dead.");
}
}
}
class ShengThread implements Runnable {
public void run() {
Process proc = null;
try
{
String osName = System.getProperty("os.name" );
String[] cmd = new String[3];
if( osName.equals( "Windows XP" ) )
{
cmd[0] = "cmd" ;
cmd[1] = "/C" ;
cmd[2] = "c:\\status.bat";
}
Runtime rt = Runtime.getRuntime();
System.out.println(osName+"Execing " + cmd[0] + " " + cmd[1]
+ " " + cmd[2]);
try {
proc = rt.exec(cmd);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// any error message?
StreamGobbler errorGobbler = new
StreamGobbler(proc.getErrorStream(), "ERROR");
// any output?
StreamGobbler outputGobbler = new
StreamGobbler(proc.getInputStream(), "OUTPUT");
// kick them off
errorGobbler.start();
outputGobbler.start();
// any error???
int exitVal = proc.waitFor();
System.out.println("ExitValue: " + exitVal);
} catch (InterruptedException t)
{
System.out.println("start\n");
proc.destroy();
t.printStackTrace();
}
}
}
The Process.destroy() method forcibly destroys an external process ... if this is possible. (In some situations you can't destroy processes, but that's only marginally relevant.)

Categories