Advanced Java tunnel - output(and errors) returned
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "pattern/myBlockingQueueAnyVersion/MyBlockingQueue" as
package pattern.myBlockingQueueAnyVersion;
public class MyBlockingQueue {
private int notifyCount = 0;
private int expectCount;
private Object lock = new Object();
class NotEnoughNotifications extends Exception {
public NotEnoughNotifications(String msg) {
super(msg);
}
}
public MyBlockingQueue(int expectCount) {
this.expectCount = expectCount;
}
public void threadIsDone() {
notifyCount++;
synchronized(lock) {
lock.notify();
}
}
/** When using the timeout you probably don't care any more of the thread
* after timeout, so remember to .setDaemon(true) on your thread*/
public void waitForThreadsDone(long timeout) throws Exception {
long callTime = System.currentTimeMillis();
long elapsedTime = 0;
while(((elapsedTime = (System.currentTimeMillis() - callTime))<timeout) &&
(notifyCount<expectCount)) {
long timeToWait = timeout-elapsedTime;
if(timeToWait>0) {
synchronized(lock) {
lock.wait(timeToWait);
}
}
}
if(notifyCount < expectCount) throw new NotEnoughNotifications(
"Timeout. Not enough finish notification received. Expected " +
expectCount + ", received " + notifyCount + ", " + elapsedTime +
" millis. elapsed, timeout was after " + timeout + " millis.");
else if (notifyCount > expectCount) throw new Exception("Too many finish " +
"notification received. Expected " + expectCount + ", received "
+ notifyCount);
}
public void waitForThreadDone() throws Exception {
boolean completionOk = false;
while(! completionOk) {
completionOk = true;
try {
waitForThreadsDone(Long.MAX_VALUE);
} catch(NotEnoughNotifications e) {
completionOk = false;
}
}
}
public static void main(String[] args) throws Exception {
args.getClass();
MyBlockingQueue lock = new MyBlockingQueue(1);
class MyThread extends Thread {
MyBlockingQueue lock;
public MyThread(MyBlockingQueue lock) {
this.lock = lock;
}
public void run() {
System.out.println("Thread done");
lock.threadIsDone();
}
};
MyThread t = new MyThread(lock);
t.start();
Thread.sleep(2000);
lock.waitForThreadDone();
}
}
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "os/oracleTunnel/advanced/StreamReader" as
package os.oracleTunnel.advanced;
import java.io.IOException;
import java.io.InputStream;
import pattern.myBlockingQueueAnyVersion.MyBlockingQueue;
public class StreamReader extends Thread {
private InputStream inputStream;
private String result = "";
private MyBlockingQueue q;
StreamReader(MyBlockingQueue q, InputStream inputStream) {
this.inputStream = inputStream;
this.q = q;
}
public void run() {
try {
byte[] buff = new byte[1000];
int read = 0;
while((read=inputStream.read(buff))!=-1) {
result = result + new String(buff, 0, read);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
q.threadIsDone();
}
}
public String getResult() {
return result;
}
}
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "os/oracleTunnel/advanced/AST" as
package os.oracleTunnel.advanced;
import pattern.myBlockingQueueAnyVersion.MyBlockingQueue;
public class AST {
public static class ECommandException extends Exception {
public ECommandException(String msg) {
super(msg);
}
}
public static String execute(String command, long timeout) throws Exception {
Runtime runtime = Runtime.getRuntime();
Process process;
//int exitValue = -1;
process = runtime.exec(command);
MyBlockingQueue q = new MyBlockingQueue(2);
StreamReader errorReader = new StreamReader(q, process.getErrorStream());
StreamReader outputReader = new StreamReader(q, process.getInputStream());
errorReader.start();
outputReader.start();
/* Do not wait for process, any error is raisen from error output.
* Any command waiting for user input will hang forever */
//exitValue = process.waitFor();
q.waitForThreadsDone(timeout);
if(errorReader.getResult().length() > 0)
throw new ECommandException(errorReader.getResult());
return outputReader.getResult();
}
public static void main(String[] args) throws Exception {
args.getClass();
System.out.println(AST.execute("cmd.exe /C dir", 10000));
}
}
Pl/Sql declaration
create or replace FUNCTION shAdv(Command IN STRING, timeout in number) RETURN varchar2 IS LANGUAGE JAVA NAME 'os.oracleTunnel.advanced.AST.execute(java.lang.String, long) return java.lang.String';
begin
dbms_output.put_line(shAdv('df -k', 10000));
end;
For more complex commands you may create a file on the OS using WriteToFile.java.sql and then execute the file
Remember a chmode +x filename |