msmolyak
asked on
Invoking UNIX shell command (mailx) from Oracle Java stored procedure
The program below is suppose do send an email using UNIX mailx program. It works correctly when I compile it in UNIX and invoke it from the command line by sending an email to the given address.
I need this program to run as a stored procedure, however. I deploy it as such and try to invoke it. It prints the results correctly to the standard output. It does not send any emails, however. One other difference in execution is that when invoked from the command line, the program takes about a minute to return. When invoked as a stored procedure in PL/SQL program or SQL*Plus anonymous block, it returns immediately.
Why would mailx invocation not work from a stored procedure? Are there other ways to invoke mailx from PL/SQL?
Here is how the Java stored procedure is invoked from SQL*Plus:
declare
mailx_result number;
begin
dbms_output.enable(100000) ;
dbms_java.set_output(10000 0);
dbms_java.grant_permission ( user, 'SYS:java.io.FilePermissio n', '<<ALL FILES>>', 'execute' );
dbms_output.put_line(to_ch ar(sysdate , 'MM/DD/YYYY HH24:MI:SS') || ' started acting_cron');
mailx_result := java_utilities.mailx('Hey there', 'Hi', 'oracle@solaris10ora', 1);
end;
Thank you.
Michael
Program code:
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter ;
public class MailUtility
{
public static void main(String[] args)
{
System.out.println(mailx(" Hey, there", "Hello", "oracle@solaris10ora", 1));
}
/**
* Sends a message using UNIX mailx command.
* @param message message contents
* @param subject message subject
* @param addressee message addressee
* @param display if greater than 0, display the command
* @return OS process return code
*/
public static int mailx(String message, String subject,
String addressee, int display)
{
System.out.println("In mailx()");
try
{
String command =
"echo \"" + message + "\" | mailx -r a@b.c" + " -s \"" + subject + "\" " + addressee;
if (display > 0)
{
System.out.println(command );
}
try
{
Process process = Runtime.getRuntime().exec( "/bin/bash ");
BufferedWriter outCommand =
new BufferedWriter(new OutputStreamWriter(process .getOutput Stream())) ;
outCommand.write(command, 0, command.length());
outCommand.newLine();
outCommand.write("exit", 0, 4);
outCommand.newLine();
outCommand.flush();
process.waitFor();
outCommand.close();
return process.exitValue();
}
catch (IOException e)
{
e.printStackTrace();
return -1;
}
}
catch (Exception e)
{
e.printStackTrace();
return -1;
}
}
}
I need this program to run as a stored procedure, however. I deploy it as such and try to invoke it. It prints the results correctly to the standard output. It does not send any emails, however. One other difference in execution is that when invoked from the command line, the program takes about a minute to return. When invoked as a stored procedure in PL/SQL program or SQL*Plus anonymous block, it returns immediately.
Why would mailx invocation not work from a stored procedure? Are there other ways to invoke mailx from PL/SQL?
Here is how the Java stored procedure is invoked from SQL*Plus:
declare
mailx_result number;
begin
dbms_output.enable(100000)
dbms_java.set_output(10000
dbms_java.grant_permission
dbms_output.put_line(to_ch
mailx_result := java_utilities.mailx('Hey there', 'Hi', 'oracle@solaris10ora', 1);
end;
Thank you.
Michael
Program code:
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter
public class MailUtility
{
public static void main(String[] args)
{
System.out.println(mailx("
}
/**
* Sends a message using UNIX mailx command.
* @param message message contents
* @param subject message subject
* @param addressee message addressee
* @param display if greater than 0, display the command
* @return OS process return code
*/
public static int mailx(String message, String subject,
String addressee, int display)
{
System.out.println("In mailx()");
try
{
String command =
"echo \"" + message + "\" | mailx -r a@b.c" + " -s \"" + subject + "\" " + addressee;
if (display > 0)
{
System.out.println(command
}
try
{
Process process = Runtime.getRuntime().exec(
BufferedWriter outCommand =
new BufferedWriter(new OutputStreamWriter(process
outCommand.write(command, 0, command.length());
outCommand.newLine();
outCommand.write("exit", 0, 4);
outCommand.newLine();
outCommand.flush();
process.waitFor();
outCommand.close();
return process.exitValue();
}
catch (IOException e)
{
e.printStackTrace();
return -1;
}
}
catch (Exception e)
{
e.printStackTrace();
return -1;
}
}
}
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ASKER
Thank you for you post, sventhan. Where do I find the Java source for ExecOSCmdLog.javaand CaptureStream.java?
Michael
Michael
SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ExecOSCmdLog.java
-------------------code begins here---------------------- ---------- ---------- ---
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class ExecOSCmdLog {
public static void doit(String args[])
{
boolean STDOUT = false;
boolean STDERR = false;
boolean LOGGER = true;
InputStream so = null;
InputStream se = null;
Thread o =null;
Thread e =null;
int rc = -1;
String cmd = "Error inproper call";
FileOutputStream fos = null;
if (args.length < 1) {
System.out.println("USAGE: java ExecOSCmdLog \'cmd\' ");
System.exit(1);
}
try {
cmd = args[0];
if (args.length >1 ) {
for (int i =1, j = args.length ; i < j; i++) {
if (args[i].equals("STDOUT")) { // out and log
STDOUT= true;
} else if (args[i].equals("STDERR")) { // out err and log
STDERR= true;
STDOUT= true;
} else if (args[i].equals("NOLOG")) { // out and no log
LOGGER= false;
STDOUT= true;
} else if (args[i].equals("NONE")) {
// eat the defaults
// nothing to the screen, do logging
} else {
fos = new FileOutputStream(args[1]);
STDOUT= true;
}
}
}
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(cmd);
so = p.getInputStream();
se = p.getErrorStream();
if (STDOUT) {
capture(so, fos, "OUT ",o);
}
if (STDERR) {
capture(se, null, "ERR ",e);
}
try {
rc = p.waitFor();
/* Handle exceptions for waitFor() */
} catch (InterruptedException intexc) {
System.out.println("Interr upted Exception on waitFor: " +
intexc.getMessage());
}
if ( o != null) {
o.join();
o = null;
}
if ( e != null) {
e.join();
e = null;
}
if (fos !=null) {
fos.flush();
fos.close();
}
se.close();
so.close();
System.out.println("ExitVa lue: " + rc);
} catch (Throwable t) {
System.out.println("ExitVa lue: " + rc);
t.printStackTrace();
} finally {
if (LOGGER) {
LogCmd(cmd,rc);
STDOUT = false;
STDERR = false;
LOGGER = true;
}
}
}
private static void capture( InputStream is,
FileOutputStream fos,
String label,
Thread o ){
CaptureStream out = new CaptureStream(is, label, fos );
o = new Thread(out);
o.start();
}
private static void LogCmd(String cmd, int rc){
try {
final String insert =
"INSERT INTO OS_CMD_LOG (CALLER,CMD,RETURN_VALUE)" +
" VALUES ( SYS_CONTEXT('USERENV', 'SESSION_USER' ), "+
" '"+ cmd + "', "+ rc + " ) " ;
// As the connection should not be closed anyway
Statement stmt =
DriverManager.getConnectio n
("jdbc:default:connection: ").createS tatement() ;
stmt.executeUpdate(insert) ;
stmt.close();
} catch (SQLException e ) {
e.printStackTrace();
}
}
}
}
-----------------code ends here---------------------- ---------- ---------- -------
and the supporting class
CaptureStream.java
-------------------code begins here---------------------- ---------- ---------- ---
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
class CaptureStream implements Runnable {
private final InputStream is;
private final String label;
private final OutputStream redirect;
private boolean redirected = false;
CaptureStream(InputStream is, String label, OutputStream redirect)
{
this.is = is;
this.label = label + "> ";
this.redirect = redirect;
}
CaptureStream(InputStream is, String label)
{
this(is, label, null);
}
CaptureStream(InputStream is)
{
this(is, " ", null);
}
public void run()
{
try {
PrintWriter pw = null;
if (redirect != null) {
pw = new PrintWriter(redirect);
redirected = true;
}
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null) {
System.out.println(label + line);
if (redirected) {
pw.println(line);
}
}
if (redirected) {
pw.flush();
pw.close();
}
br.close();
isr.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
-----------------code ends here---------------------- ---------- ---------- -------
-------------------code begins here----------------------
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class ExecOSCmdLog {
public static void doit(String args[])
{
boolean STDOUT = false;
boolean STDERR = false;
boolean LOGGER = true;
InputStream so = null;
InputStream se = null;
Thread o =null;
Thread e =null;
int rc = -1;
String cmd = "Error inproper call";
FileOutputStream fos = null;
if (args.length < 1) {
System.out.println("USAGE:
System.exit(1);
}
try {
cmd = args[0];
if (args.length >1 ) {
for (int i =1, j = args.length ; i < j; i++) {
if (args[i].equals("STDOUT"))
STDOUT= true;
} else if (args[i].equals("STDERR"))
STDERR= true;
STDOUT= true;
} else if (args[i].equals("NOLOG")) { // out and no log
LOGGER= false;
STDOUT= true;
} else if (args[i].equals("NONE")) {
// eat the defaults
// nothing to the screen, do logging
} else {
fos = new FileOutputStream(args[1]);
STDOUT= true;
}
}
}
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(cmd);
so = p.getInputStream();
se = p.getErrorStream();
if (STDOUT) {
capture(so, fos, "OUT ",o);
}
if (STDERR) {
capture(se, null, "ERR ",e);
}
try {
rc = p.waitFor();
/* Handle exceptions for waitFor() */
} catch (InterruptedException intexc) {
System.out.println("Interr
intexc.getMessage());
}
if ( o != null) {
o.join();
o = null;
}
if ( e != null) {
e.join();
e = null;
}
if (fos !=null) {
fos.flush();
fos.close();
}
se.close();
so.close();
System.out.println("ExitVa
} catch (Throwable t) {
System.out.println("ExitVa
t.printStackTrace();
} finally {
if (LOGGER) {
LogCmd(cmd,rc);
STDOUT = false;
STDERR = false;
LOGGER = true;
}
}
}
private static void capture( InputStream is,
FileOutputStream fos,
String label,
Thread o ){
CaptureStream out = new CaptureStream(is, label, fos );
o = new Thread(out);
o.start();
}
private static void LogCmd(String cmd, int rc){
try {
final String insert =
"INSERT INTO OS_CMD_LOG (CALLER,CMD,RETURN_VALUE)"
" VALUES ( SYS_CONTEXT('USERENV', 'SESSION_USER' ), "+
" '"+ cmd + "', "+ rc + " ) " ;
// As the connection should not be closed anyway
Statement stmt =
DriverManager.getConnectio
("jdbc:default:connection:
stmt.executeUpdate(insert)
stmt.close();
} catch (SQLException e ) {
e.printStackTrace();
}
}
}
}
-----------------code ends here----------------------
and the supporting class
CaptureStream.java
-------------------code begins here----------------------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
class CaptureStream implements Runnable {
private final InputStream is;
private final String label;
private final OutputStream redirect;
private boolean redirected = false;
CaptureStream(InputStream is, String label, OutputStream redirect)
{
this.is = is;
this.label = label + "> ";
this.redirect = redirect;
}
CaptureStream(InputStream is, String label)
{
this(is, label, null);
}
CaptureStream(InputStream is)
{
this(is, " ", null);
}
public void run()
{
try {
PrintWriter pw = null;
if (redirect != null) {
pw = new PrintWriter(redirect);
redirected = true;
}
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null) {
System.out.println(label + line);
if (redirected) {
pw.println(line);
}
}
if (redirected) {
pw.flush();
pw.close();
}
br.close();
isr.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
-----------------code ends here----------------------
Please let me know if you need any sample.