I tried with the below linked steps:
https://slobaray.com/tag/execute-shell-script-from-plsql/
It consists in
creating a java object stored as BASH_OS function with
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "BASH_OS"..
Then to execute the java with
CREATE OR REPLACE PROCEDURE unix_command (p_command IN VARCHAR2)
AS LANGUAGE JAVA
NAME 'BASH_OS.executeCommand (java.lang.String)';
But It shows that
the object BASH_OS does not exist.
Can any one help me on how we can execute the shell script from the Toad with this method?
or Is there any other method to call shell script from Toad?
Referring your link, I found that the class name in line 13 is wrong for creating BASH_OS.
The class name should be "BASH_OS" instead of "Host". Since there is no comment feature on the blog, so i copy the fixed code here.
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "BASH_OS" AS
/******************************************************************************
NAME: BASH_OS
PURPOSE: To perform the shell command using Java class
REVISIONS:
Ver Date Author Description
--------- ---------- ------ ---------------------------------------------
0.1 <<>> S.Ray Initial Version
******************************************************************************/
import java.io.*;
/* public class Host { <-- THIS IS WRONG */
public class BASH_OS {
public static void executeCommand(String command) {
try {
String[] finalCommand;
{
finalCommand = new String[3];
finalCommand[0] = "/bin/sh";
finalCommand[1] = "-c";
finalCommand[2] = command;
}
final Process pr = Runtime.getRuntime().exec(finalCommand);
pr.waitFor();
new Thread(new Runnable(){
public void run() {
BufferedReader br_in = null;
try {
br_in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String buff = null;
while ((buff = br_in.readLine()) != null) {
System.out.println("Process out :" + buff);
try {Thread.sleep(100); } catch(Exception e) {}
}
br_in.close();
}
catch (IOException ioe) {
System.out.println("Exception caught printing process output.");
ioe.printStackTrace();
}
finally {
try {
br_in.close();
} catch (Exception ex) {}
}
}
}).start();
new Thread(new Runnable(){
public void run() {
BufferedReader br_err = null;
try {
br_err = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
String buff = null;
while ((buff = br_err.readLine()) != null) {
System.out.println("Process err :" + buff);
try {Thread.sleep(100); } catch(Exception e) {}
}
br_err.close();
}
catch (IOException ioe) {
System.out.println("Exception caught printing process error.");
ioe.printStackTrace();
}
finally {
try {
br_err.close();
} catch (Exception ex) {}
}
}
}).start();
}
catch (Exception ex) {
System.out.println(ex.getLocalizedMessage());
}
}
};
Related
Java 8
import java.util.zip.GZIPOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
private void createFile(final String json) throws IOException {
final String fileName = getConfigFileName(this.getSomePath());
GZIPOutputStream out = null;
try {
out = new GZIPOutputStream(new FileOutputStream(fileName + ".gz"));
out.write(json.getBytes());
} catch (IOException e) {
throw e;
} finally {
try {
if (out != null) {
out.finish();
out.close();
}
} catch (IOException e) {
LOGGER.error("createFile: IOException while closing resources", e);
}
}
}
Nice. This work fine.
Now I want to use try-with-resource
private void createFile(final String json) throws IOException {
final String fileName = getConfigFileName(this.getSomeFile());
try (GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(fileName + ".gz"))) {
out.write(json.getBytes());
} catch (IOException e) {
throw e;
} finally {
try {
if (out != null) {
out.finish();
}
} catch (IOException e) {
LOGGER.error("createFile: IOException while closing resources", e);
}
}
}
But now I get error in this line:
if (out != null) {
Error is:
out cannot be resolved
I know this error is rise because variable out is on finally section.
But how I can use try-with-resources and execute method out.finish ?
From a technical perspective - a variable declared in the try argument isn't available in the finally clause, as you've seen. The good news here is that from a function perspective - finish() shouldn't be in the finally block anyway. finish is part of the positive (a.k.a "happy") flow, and should only be called when you're done writing to the stream. In other words, if the write operation failed and an exception was thrown, you shouldn't call finish anyway.
To make a long story short - move the finish call inside the try block:
Side note: Since your method throws an IOException, there's no reason to catch the exception and rethrow it. You can clean up the code by allowing it to be thrown from the method call directly:
private void createFile(final String json) throws IOException {
final String fileName = getConfigFileName(this.getSomeFile());
try (GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(fileName + ".gz"))) {
out.write(json.getBytes());
out.finish();
}
}
I'm implementing a mail Sender, near 1'6000.000 mails (with images and PDF) in one day per month (closing month extract), the mails are about 12 products...
I need to fill a Message Scratch per product... in order to not read (per email) else per product.
I'm trying to implement cloning javax.mail.Message and javax.mail.Multipart in order to be faster.
AddContent to Multipart
public static void addContent(final Multipart multipart, String contenidoCorreo) throws Exception {
MimeBodyPart mimeBodyPart = new PreencodedMimeBodyPart("8bit");
mimeBodyPart.setText(contenidoCorreo, "iso-8859-1", "html");
multipart.addBodyPart(mimeBodyPart, 0);
}
Add Image per Bytes
public static void addImageToMultipart(final Multipart multipart, byte[] contenidoImagen, String nombreImagen) throws Exception {
MimeBodyPart imagenMimeBodyPart = new MimeBodyPart();
try {
ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource(contenidoImagen, "image/*");
imagenMimeBodyPart.setDataHandler(new DataHandler(byteArrayDataSource));
imagenMimeBodyPart.setFileName(nombreImagen);
imagenMimeBodyPart.setContentID("<" + nombreImagen + ">");
imagenMimeBodyPart.setDisposition(MimeBodyPart.INLINE);
multipart.addBodyPart(imagenMimeBodyPart);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
AddPDF per File
public static void addPDF(final Multipart multipart, String ruta, String nombre) throws Exception {
Path path = Paths.get(ruta, nombre);
if (path.toFile().exists()) {
MimeBodyPart preencodedMimeBodyPart = new PreencodedMimeBodyPart("base64");
preencodedMimeBodyPart.attachFile(path.toFile());
preencodedMimeBodyPart.setFileName(nombre);
preencodedMimeBodyPart.setHeader("Content-Type", "application/pdf");
preencodedMimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT);
multipart.addBodyPart(preencodedMimeBodyPart);
MimeBodyPart pdfMimeBodyPart = new MimeBodyPart();
}
My Cloning Message
public static Message cloneMessage(Message source) {
//Multiple and Separated Exceptions because maybe not all properties are defined in some time.
Message target = new MimeMessage(source.getSession());
try {
if (source.getFrom() != null && source.getFrom().length > 0) {
Address address = (source.getFrom()[0]);
target.setFrom(new InternetAddress(((InternetAddress) address).getAddress(), ((InternetAddress) address).getPersonal()));
}
} catch (Exception ex) {
//Handle Exception
}
try {
target.setSentDate((Date) (source.getSentDate().clone()));
} catch (MessagingException ex) {
//Handle Exception
}
try {
target.setRecipients(Message.RecipientType.TO, target.getRecipients(Message.RecipientType.TO).clone());
} catch (MessagingException ex) {
//Handle Exception
}
try {
Enumeration numerationHeaders = source.getAllHeaders();
while (numerationHeaders.hasMoreElements()) {
Header header = (Header) numerationHeaders.nextElement();
target.addHeader(header.getName(), header.getValue());
}
} catch (MessagingException ex) {
//Handle Exception
}
try {
target.setSubject(new String(source.getSubject()));
} catch (MessagingException ex) {
//Handle Exception
}
try {
target.setContent(cloneMultipart((Multipart)(source.getContent())));
} catch (Exception ex) {
//Handle Exception
}
return target;
}
Cloning Multipart
public static Multipart cloneMultipart(Multipart source) {
MimeMultipart target = new MimeMultipart();
try {
for (int i = 0; i < source.getCount(); i++) {
MimeBodyPart mimeBodyPart = (MimeBodyPart)source.getBodyPart(i);
mimeBodyPart //?????
}
} catch (MessagingException ex) {
//Handle Exception
}
return target;
}
How cloning Multipart?
some advice to clone Message?
How detect the Content (the used with addContent method) has been added?
I have an insert/update trigger for a Oracle table.
Is there a way to send the details of the affected row(all columns) as a message to JMS?
I can write a Java Program, 'loadjava' that and call from the trigger.
Does this way affect performance?
Is there any native way of achieving this?
There is indeed a native way: use AQ JMS from PL/SQL, see https://docs.oracle.com/database/121/ADQUE/jm_exmpl.htm#ADQUE1600. In short you create an AQ queue with a JMS payload type; then you can post messages with PL/SQL from the trigger. An external Java client can connect to the database and read the messages with JMS.
I don't know how much a call into Java would affect performance, but I try to avoid it. It was a nice idea but it never really caught on, so it remains a fringe case and at least early on there were always issues. PL/SQL on the other hand works.
If you need to send data to another message queue product (tags activemq and mq) you can read the messages in Java and forward them. It adds an extra step, but it is straightforward.
loadjava have many problems and not stable if there is many classes loaded and many business, take a look Calling Java from Oracle, PLSQL causing oracle.aurora.vm.ReadOnlyObjectException
Oracle AQ as i know is not free.
I have implemented the same need after trying many possibilities by creating only 1 class loaded to oracle with loadjava which is called as a procedure by a trigger and have the responsability to call an external java program with all needed parameters and log external process output to a table, as below.
i have encoded text mesage to BASE64 because i used JSON format and some specials caracters can causes problems as a parameters to external java program.
i have used "#*#jms_separator#*#" as a separator in the sent parameter string to parse the content if i need to send many parameters to the external program.
the whole duration of ShellExecutor.shellExec is around 500ms and running since 1 year without any problem.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Arrays;
import java.util.concurrent.FutureTask;
import sun.misc.BASE64Encoder;
public class ShellExecutor {
static {
System.setProperty("file.encoding", "UTF-8");
}
private static final String INSERT_LOGS_SQL = "INSERT INTO JMS_LOG (TEXT_LOG) VALUES (?) ";
private static final String DEFAULT_CONNECTION = "jdbc:default:connection:";
public static String SQLshellExec(String command) throws Exception {
long start = System.currentTimeMillis();
StringBuffer result = new StringBuffer();
ShellExecutor worker = new ShellExecutor();
try {
worker.shellExec(command, result);
} finally {
result.append("exe duration : " + (System.currentTimeMillis() - start + "\n"));
Connection dbConnection = null;
PreparedStatement logsStatement = null;
try {
dbConnection = DriverManager.getConnection(DEFAULT_CONNECTION);
logsStatement = dbConnection.prepareStatement(INSERT_LOGS_SQL);
logsStatement.clearParameters();
Clob clob = dbConnection.createClob();
clob.setString(1, result.toString());
logsStatement.setClob(1, clob);
logsStatement.executeUpdate();
} finally {
if (logsStatement != null) {
try {
logsStatement.close();
} catch (Exception e) {
}
}
}
}
return result.substring(result.length() - 3090);
}
public void shellExec(String command, StringBuffer result) throws Exception {
Process process = null;
int exit = -10;
try {
InputStream stdout = null;
String[] params = command.split("#*#jms_separator#*#");
BASE64Encoder benc = new BASE64Encoder();
for (int i = 0; i < params.length; i++) {
if (params[i].contains("{") || params[i].contains("}") || params[i].contains("<")
|| params[i].contains("/>")) {
params[i] = benc.encodeBuffer(params[i].getBytes("UTF-8"));
}
}
result.append("Using separator : " + "#*#jms_separator#*#").append("\n")
.append("Calling : " + Arrays.toString(params)).append("\n");
ProcessBuilder pb = new ProcessBuilder(params);
pb.redirectErrorStream(true);
process = pb.start();
stdout = process.getInputStream();
LogStreamReader lsr = new LogStreamReader(stdout, result);
FutureTask<String> stdoutFuture = new FutureTask<String>(lsr, null);
Thread thread = new Thread(stdoutFuture, "LogStreamReader");
thread.start();
try {
exit = process.waitFor();
} catch (InterruptedException e) {
try {
exit = process.waitFor();
} catch (Exception e1) {
}
}
stdoutFuture.get();
result.append("\n").append("exit code :").append(exit).append("\n");
if (exit != 0) {
throw new RuntimeException(result.toString());
}
} catch (Exception e) {
result.append("\nException(").append(e.toString()).append("):").append(e.getCause()).append("\n\n");
e.printStackTrace(System.err);
throw e;
} finally {
if (process != null) {
process.destroy();
}
}
}
}
class LogStreamReader implements Runnable {
private BufferedReader reader;
private StringBuffer result;
public LogStreamReader(InputStream is, StringBuffer result) {
this.reader = new BufferedReader(new InputStreamReader(is));
this.result = result;
}
public void run() {
try {
String line = null;
while ((line = reader.readLine()) != null) {
result.append(line).append("\n");
}
} catch (Exception e) {
result.append("\nException(").append(e.toString()).append("):").append(e.getCause()).append("\n\n");
e.printStackTrace(System.err);
} finally {
try {
reader.close();
} catch (IOException e) {
}
}
}
}
The class of the external Java program packaged as an executable with all needed librairies, a simple JMS sender :
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.commons.codec.binary.Base64;
import org.json.JSONObject;
import progress.message.jclient.ConnectionFactory;
import progress.message.jimpl.Connection;
public class JMSSender {
private static SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS");
public static void main(String[] args) throws Throwable {
doSend(args[0]);
}
public static void doSend(String text)
throws Throwable {
if (Base64.isBase64(text)) {
text = new String(Base64.decodeBase64(text));
}
String content = "\n\nsending message :" + text;
Connection con = null;
Session session = null;
try {
ConnectionFactory cf = new ConnectionFactory();
session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination dest = session.createTopic(destination) ;
MessageProducer producer = session.createProducer(dest);
con.start();
JSONObject json = new JSONObject();
json.put("content", text);
json.put("date", sdf.format(new Date()));
TextMessage tm = session.createTextMessage(json.toString());
producer.send(tm);
content += " \n\n" + "sent message :" + json.toString();
} catch (Throwable e) {
content += " \n\n" + e.toString() + " \n\n" + Arrays.toString(e.getStackTrace());
if (e.getCause() != null) {
content += " \n\nCause : " + e.getCause().toString() + " \n\n"
+ Arrays.toString(e.getCause().getStackTrace());
}
e.printStackTrace(System.err);
throw e;
} finally {
write("steps on sending message : " + content);
if (session != null) {
try {
session.commit();
session.close();
} catch (Exception e) {
}
session = null;
}
if (con != null) {
try {
con.stop();
con.close();
} catch (Exception e) {
}
}
}
}
private static void write(String log) {
try {
if (System.out != null) {
System.out.println(log);
}
} catch (Exception e2) {
}
}
}
So i hava an oracle functiion like: function unbind (ids in id_table). It takes an array of ids to perform some updates on my database.
The question is how can I run my function in order to perform update operations?
What I've alreade tried:
1. Query query = getSession().createSQLQuery("call UNBIND(:ids)");
query.setParameter("ids", myIds);
query.executeUpdate();
but I got ora-06576 not a valid function or procedure name
Query query = getSession().createSQLQuery("execute UNBIND(:ids)");
query.setParameter("ids", myIds);
query.executeUpdate();
finish with ora-00900 invalid sql statement
Long [] myArray = movedIds.toArray(new Long[movedIds.size()]);
Boolean result = getSession().doReturningWork(new ReturningWork<Boolean>() {
#Override
public Boolean execute(Connection connection) throws SQLException {
CallableStatement callableStatement = connection.prepareCall("{ ? = call UNBIND(:ids)");
callableStatement.registerOutParameter(1, Types.INTEGER);
callableStatement.setArray(2, connection.createArrayOf("id_table", myArray));
callableStatement.execute();
return !(callableStatement.getInt(1) == 0);
}
});
finishes with java.sql.sqlfeaturenotsupportedexception unsupported feature
The app conects to the database via jboss, so I suppose that could be the problem in p. 3?
SELECT
UNBIND( id_table (6271789) ) FROM DUAL
does not work because my function performs updates...
Anyway is there any other method to run a function that takes an array as a parameter directly from java code?
here is a simple example, does this help?
import java.sql.*;
public class Class1 {
public static void main(String[] args) throws SQLException {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Connection conn = null;
try {
conn = DriverManager.getConnection(
"jdbc:oracle:thin:#//localhost/orcl","scott","tiger");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String query = "{ ? = call test_func(?) }";
CallableStatement cs = null;
try {
cs = conn.prepareCall(query);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int inVal = 0;
cs.setInt(2, inVal);
cs.registerOutParameter(1, oracle.jdbc.OracleTypes.NUMBER);
cs.executeUpdate();
int res = cs.getInt(1);
System.out.println("result is " + res);
}
}
Well always teach me this way of open and close connections from database, then i search more and more because this is very important for the performance of my application.
Here is my Class connection
public class Connection {
jdbc:oracle:thin:#//xxx.xx.x.xxx:xxxx/xxxxx.xxxxxx.xxxxx.xxx;
protected static Connection cn = null;
protected Connection getCn() {
return cn;
}
public static void setCn(Connection cn) {
Connection.cn = cn;
}
public ResultSet select(String sql) throws Exception {
ResultSet rs = null;
Statement st = null;
try {
st = this.getCn().createStatement();
rs = st.executeQuery(sql);
} catch (java.sql.SQLException e) {
throw e;
}
return rs;
}
public void insert(String sql) throws Exception {
Statement st = null;
try {
st = this.getCn().createStatement();
st.executeUpdate(sql);
} catch (java.sql.SQLException e) {
throw e;
}
}
public Connection connect() throws Exception {
try {
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
setCn(DriverManager.getConnection(DBURL, "user", "password"));
} catch (java.sql.SQLException e) {
throw e;
}
return cn;
}
Well that was for my Connection Class, now here i have some others class that extends from my Connection class to bring me data from the DataBase.
public String checkMethod() throws Exception {
ResultSet rs;
String sql = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
try {
this.connect();
rs = this.select(sql);
while (rs.next()) {
//some data collect
}
rs.close(); //here is my dude because when may i can put the statement.close() line?
} catch (Exception e) {
throw e;
} finally {
this.cerrar();
}
return "success";
}
im using jsf and oracle, i think this snippet should be in my class Connection after the catch but generates me and error of the resulset is closed when i execute the method rs.next() and is logic because the statement must be close after the reading data of the resultSet, so how can i close the statement in my class Connection or in other place??? any suggestions? please help me
finally {
if (st != null) {
st.close();
}
}
A quick fix to the problem is:
finally {
try{ st.close(); }catch( Exception ex ) { /* do nothing*/ }
}
this prevents from throwing an error when something goes wrong with the statement in other places of the code ( st is null, st is closed etc.).
A more elegant solution might be creating a helper class with methods that close statements, resultsets etc. and hide exceptions that occur:
class DbCloser{
static void closeQuietly( Statement st ){
try{
st.close();
} catch( Exception ex ){
/* do nothing */
}
}
static void closeQuietly( ResultSet rs ){
try{
rs.close();
} catch( Exception ex ){
/* do nothing */
}
}
// .... etc.
}
and then use that helper class in finally blocks in code:
finally {
DbCloser.closeQuietly( st );
}
There is ready-made DbUtils package from Appache Commons that has already implemented such helper methods, just download this library and place it in the class-path, see this links for details:
http://commons.apache.org/proper/commons-dbutils/
http://commons.apache.org/proper/commons-dbutils/apidocs/index.html
And finally I would suggest to place close methods only in finnaly blocks:
try {
......
rs = this.select(sql);
.......
...........
// Do not close the statement here ......
// rs.close(); //here is my dude because when may i can put the statement.close() line?
} catch (Exception e) {
throw e;
} finally {
// ..... always close it here !!!
DbUtils.closeQuietly( st );
.........
}
i use this one
finally {
try{
if(st!=null){
st.close();
st=null;
}
}catch( Exception ex )
{
/* you can log this*/
}
}
Finally, I solved it like this:
public String checkMethod() throws Exception {
ResultSet rs;
String sql = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
try {
this.connect();
rs = this.select(sql);
while (rs.next()) {
//some data collect
}
rs.close();
rs.getStatement().close(); 'This works for me =)
} catch (Exception e) {
throw e;
} finally {
this.cerrar();
}
return "success";
}