Appeler une Class Java à partir d'un Bloc PL/SQL

Il est parfois nécessaire d’appeler une Class à partir d’un bloc PL/SQL pour des traitements spécifiques comme par exemple le cryptage ou bien l’analyse d’expression Quartz. Dans l’article ci-dessous, j’aborderai l’appel d’une Class de Cryptage dont le source est en annexe à la fin de l’article.

  • Compilation de la Class java

Il faut impérativement compiler la Class dans une version de java identique à celle du serveur de base de données.
Exemple :
Si la version de Java du serveur BDD est en 1.5 et que celle de l’IDE est en 1.7, il faut ajouter les mots clefs suivants lors de la compilation : -source 1.5 -target 1.5 sinon l’erreur suivante se produit lors de l’exécution
de la fonction PL/SQL

ORA-29532: appel Java arrêté par une exception Java non interceptée : System error : java/lang/UnsupportedClassVersionError
ORA-06512: à ".....", ligne 1
ORA-06512: à ligne 4
  • Chargement de la Class dans la BDD

Certaines Class pouvant faire appel à des libraires, il faut donc les charger avant la Class fonctionnelle. Dans notre exemple, la Class d’encrytage fait appel aux librairies suivantes :

  • log4j-1.2.14.jar
  • commons-logging-api-1.1.jar
  • xmlsec-1.4.2.jar

Après avoir téléchargé les librairies et la Class sur le serveur de BDD (par exemple dans  /home/oracle/java4oracle/), ouvrir une session sur le serveur (par exemple Putty) avec un profil Oracle puis lancer les commandes suivantes :

loadjava -verbose -genmissing -user user1 /home/oracle/java4oracle/log4j-1.2.14.jar
loadjava -verbose -genmissing -user user1 /home/oracle/java4oracle/commons-logging-api-1.1.jar
loadjava -verbose -genmissing -user user1 /home/oracle/java4oracle/xmlsec-1.4.2.jar
loadjava -verbose -resolve -user user1 /home/oracle/java4oracle/DataEncryption.class

Le mot clef –genmissing permet de ne pas résoudre les références au moment du chargement des librairies. Cette résolution s’effectuera lors du chargement de la Class proprement dite avec le mot clef –resolve.

  • Création de la fonction PL/SQL

Sous SQLPLUS, créer la fonction suivante :

CREATE OR REPLACE FUNCTION FCT_ENCRYPT (plainText VARCHAR2, encryptProperties VARCHAR2)
RETURN VARCHAR2
AS LANGUAGE JAVA NAME 'com/..../..../..../DataEncryption.encrypt(java.lang.String,java.lang.String) return java.lang.String';
  • Test de la fonction PL/SQL

Sous SQLPLUS,

select FCT_ENCRYPT('Chaine de caractère à crypter','true') from dual;

Annexe : Code source Class Java

package com...;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.log4j.Logger;
import org.apache.xml.security.exceptions.Base64DecodingException;
import org.apache.xml.security.utils.Base64;
public class DataEncryption {
public DataEncryption() {
super();
}
/**
* @param plainText
*                  String that must be encrypted
* @param encryptProperties
*                  Only if the propertie insert.crypt of the file properties is set
*                  to true, input data is encrypted.
*
* @return
*            Encrypted string
* @throws Exception
*/
Public static String encrypt(final String plainText,final String encryptProperties ) {
....
....
....
return plainText;
}
}
}