| In
questo articolo verrà analizzata una caratteristica di
Oracle8i che permette di richiamare classi java da procedure
PL/SQL.
Nella
versione di Oracle 8i è incluso un prodotto denominato
JServer, che contiene i seguenti elementi:
· Java Virtual Machine di Oracle, chiamata Aurora,
ovvero l'ambiente di esecuzione e le librerie Java.
· Una stretta integrazione tra le funzionalità
dell' RDBMS e PL/SQL.
· JServer Accelerator (compilatore) (disponibile solamente
nella versione 8.1.6 della Enterprise Edition).
L'Aurora
JVM permette di eseguire metodi e classi java come se fossero
allocate direttamente nel database, essa fornisce un ambiente
run-time per gli oggetti Java avendo a disposizione tutte
le librerie di Java, comprese java.lang , java.io , java.net
, java.math e java.util.
Per memorizzare le classi Java in un database Oracle, bisogna
utilizzare l'utility LOADJAVA da riga di comando e non si
può accedere mai direttamente a queste classi, ma soltanto
Aurora JVM le utilizza.
Aurora JVM include un compilatore che traduce i sorgenti Java
in un file con estensione .class chiamato anche bytecode (linguaggio
esadecimale standard) .
Per eseguire i programmi Java, Aurora JVM include un interprete
che permette di far girare i .class sul sistema .
Per
poter eseguire una classe Java da Oracle è necessario
seguire i seguenti punti:
·
Installare la JDK
· Creare una classe Java e compilarla per ottenere
il file .class
· Settare gli adeguati privilegi.
· Caricare la classe in Oracle tramite il comando 'LOADJAVA'
da prompt oppure tramite il comando 'CREATE JAVA'
· Scrivere una procedura PL/SQL che esegua la chiamata
alla classe Java.
· Richiamare la procedura PL/SQL che fa eseguire la
classe Java.
Oracle8
i ha creato due nuovi ruoli per mantenere la sicurezza di
Java. Per molte operazioni eseguite da Java non saranno necessari
questi ruoli, ma se si desidera accedere o modificare file
sarà necessario averne i permessi:
Sarà
sufficiente assegnare questi ruoli come qualsiasi altro ruolo
della basedati. Per esempio, se volessi permettere all'utente
SCOTT di effettuare qualsiasi operazione tramite le classi
java basterà
che l'utente SYS o SYSTEM gli assegni questo ruolo:
GRANT JAVASYSPRIV TO SCOTT;
Se
invece volessi porre delle limitazioni a SCOTT gli assegnerei
il seguente ruolo:
GRANT JAVAUSERPRIV TO SCOTT;
Un
esempio della differenza tra i due ruoli sta nel fatto che
se volessi permettere a SCOTT di creare un file tramite Java
avrebbe bisogno di JAVASYSPRIV, per limitarlo invece nella
sola lettura o scrittura di file sarà sufficiente JAVAUSERPRIV.
Quando
viene inizializzata la JVM Aurora, essa crea un istanza di
java.lang.SecurityManager (Gestore della sicurezza di Java).
Ad ogni utente verrà assegnato un ID dinamico che corrisponde
alla sessione a cui può accedere l'utente tramite la
classe Java lanciata da PL/SQL.
Se un utente non ha i privilegi assegnati da questi ruoli
e prova ad eseguire un operazione che invece li richiederebbero,
la JVM solleverebbe l'eccezione java.lang.SecurityException.
Il messaggio di errore che comparirebbe sulla shall di SQL/PLUS
è:
ORA-29532: Java
call terminated by uncaught Java exception:
java.lang.SecurityException
L'utility LOADJAVA eseguito da riga di comando permette di
caricare nel DB i file Java.
La prima volta che si lancia LOADJAVA in uno schema vengono
creati una serie di elementi:
·
CREATE$JAVA$LOB$TABLE
Una tabella creata in ogni schema contenente gli elementi
del codice java.
·
JAVA$CLASS$MD5$TABLE
Un Hashtable utilizzata per puntare a tutti gli elementi java
caricati in ogni schema
·
LOADLOBS
Un package installato in ogni schema, utilizzato per caricare
codice java sotto forma di oggetti LOBs nel DB.
Uilizzando
LOADLOB, loadjava sposta il file java in un campo BLOB della
tabella CREATE$JAVA$LOB$TABLE e nello stesso tempo controlla
i valori della tabella JAVA$CLASS$MD5$TABLE.MD5 per verificare
se la classe era stata già caricata in precedenza e
se ha subito delle modifiche.
Questo
caricamento avviene solamente se:
La
classe si sta caricando per la prima volta o se ha subito
delle modifiche.
La sintassi è
la seguente:
loadjava {-user |
-u} username/password[@database]
[-option_name [-option_name] ...] filename [filename ]...
Nel
nostro caso:
loadjava -user scott/tiger[@host_name:port:sid]
-thin InserisciDip.class
Dopo
aver caricato la nostra classe sul db sarà necessario
creare una procedura PL/SQL tramite cui verrà chiamata
la classe java:
create procedure
Nome_procedura(par1, par2) is
LANGUAGE JAVA NAME
('nome_classe.nome_metodo(java.lang.String, java.lang.String)');
End;
Nel
nostro caso:
create procedure
Aggiorna(par1, par2) is
LANGUAGE JAVA NAME
('InserisciDip.addDept(java.lang.String, java.lang.String');
End;
A
questo punto sarà sufficiente far eseguire da SQL/PLUS:
execute Aggiorna
('Marco', 'Rossi');
ed avremo aggiornato
il db tramite il codice PL/SQL scritto in una classe Java.
Di seguito è riportato
un esempio di classe java che effettua un inserimento nella
tabella dept tramite due paramentri che gli verranno passati
dalla procedura PL/SQL:
import java.sql.*;
import oracle.jdbc.driver.*;
public class InserisciDip
{
public static void addDept (String deptName, String deptLoc) throws SQLException
{
//Creo una connessione
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:scott/tiger@HOSTNAME:PORT:SID");
String sql = "SELECT max(deptno)+1 FROM dept";
String sql2 = "INSERT INTO dept VALUES (?, ?, ?)";
int deptID = 0;
try
{
//faccio eseguire la prima select
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rset = pstmt.executeQuery();
while (rset.next()) {deptID = rset.getInt(1);}
//setto i valori di deptName e deptLoc valorizzati da input
pstmt = conn.prepareStatement(sql2);
pstmt.setInt(1, deptID);
pstmt.setString(2, deptName);
pstmt.setString(3, deptLoc);
//eseguo insert
pstmt.executeUpdate();
//chiudo il ResultSet, il PreparedStatement e la connessione
rset.close();
pstmt.close();
conn.close();
}
catch (SQLException e)
{System.err.println(e.getMessage());}
}
}
|