32 Tips&techniques Philippe Daucourt, HEG Haute école de gestion Arc Java au cœur de la base de données Oracle Depuis la version 8i, Oracle embarque une machine virtuelle Java (JVM) au cœur de sa base de données. Cette caractéristique encore mal connue des développeurs et peu répandue continue d évoluer et la version 11g a apporté son lot de nouveautés et d amélioration. Cet article revient sur les fondamentaux de cette technologie que nous avons eue l occasion de mettre en œuvre récemment dans le cadre d un projet de recherche appliquée financé par la Commission pour la technologie et l innovation de la Confédération (CTI). Les manipulations que nous allons présenter dans cet article s appliquent à une base de données 11gR2 et se baseront sur le code source Java suivant: package ch.hegarc.helloworld; public class Main { public static void main(string[] args) { System.out.println( Hello + args[0]+!!! ); Selon la tradition de Ritchie et Kernighan, cette classe Java ne fait rien d autre que de récupérer la valeur passée en paramètre au moment de l appel, de la concaténer à une chaîne de caractères puis d afficher le résultat sur la sortie standard du système. Malgré sa simplicité, ce bout de code Java pose un certain nombre de questions pour être exécuté par la base de données. Comment charger ce code source dans la base de données? Comment compiler ce code source en code Java exécutable? Comment invoquer ce traitement? Comment passer un paramètre au moment de l appel? Comment rediriger la sortie de Java vers celui de la base de données? C est à ces quelques questions que nous allons tenter de répondre dans la suite de cet article. Chargement de code Java dans la base de données Pour commencer, nous allons voir une première méthode qui consiste à charger le code source de la classe dans la base de données et à le compiler au moyen de l instruction SQL suivante: CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED ch.hegarc.helloworld.main AS package ch.hegarc.helloworld; public class Main { public static void main(string[] args) { System.out.println( Hello + args[0]+!!! ); Cette instruction a pour effet de créer un objet de type «Java Source» ainsi qu un objet de type «Java Class» dans le schéma de l utilisateur qui l a exécutée. Le nom indiqué entre «NA- MED» et «AS» correspond au nom de la source Java. Le nom de la classe
Tips&techniques 33 A N Z E I G E 5% Rabatt auf Oracle- und Oracle-Java- Seminare für SOUG-Mitglieder Drive your life. Java correspond quant à elle comme à l accoutumée en Java à la combinaison du nom du paquetage et du nom de la classe. Bien que cela ne soit pas obligatoire, nous recommandons de conserver le même nom pour ces deux objets. bien la présence de ces deux objets. Nous constatons également que les «.» dans les noms de ces objets ont été remplacés automatiquement par des «/». Il s agit bien ici de donner le nom de l objet de type «Java Source». L objet correspondant à la classe compilée sera quant à lui automatiquement supprimé. Nous allons maintenant nous intéresser à une seconde méthode pour charger du code Java dans la base de données. Cette autre solution consiste à ne charger cette fois-ci que la classe compilée. Pour cela, nous allons recourir à un utilitaire en ligne de commande qui s appelle «loadjava». La classe doit avoir été compilée au préalable soit en ligne de commande avec l utilitaire «javac» du Java Development Kit (JDK) soit en passant par les services d un environnement de développement intégré (IDE) comme NetBeans, Eclipse ou JDeveloper. Le code compilé doit correspondre à du bytecode Java 1.5. Voici la structure de la commande qui nous permet de charger notre classe dans le schéma de l utilisateur: Cette première technique de chargement permet de stocker le code source de la classe Java dans la base de données ce qui nous évite de devoir le conserver dans un autre référentiel externe. Néanmoins, cette solution comporte certaines limites puisque le compilateur interne de la base de données ne semble pas toujours compatible à 100% avec la spécification Java. Nous avons par exemple constaté que celui-ci accepte certaines annotations («@Inherited» et «@Retention») mais pas d autres («@Override»). D autre part, la base de données ne supporte actuellement que du code Java 1.5. La suppression de ces deux objets se fait au moyen de l instruction SQL suivante: loadjava -u user/password@host:port:sid -r -v -f Main.class L option «-u» permet de spécifier un schéma cible. L option «-r» permet de «résoudre» la classe avec le «resolver 1» par défaut. Nous n aborderons pas ce concept dans le cadre de cet article. L option «-v» permet d activer le mode «verbose» qui affiche plus d informations à l écran. L option «-f» permet de forcer le chargement et d écraser la classe qui porterait le même nom dans le schéma. «Main.class» correspond au nom du fichier se trouvant dans le répertoire courant contenant le code compilé. DROP JAVA SOURCE ch/hegarc/helloworld/main ; 1 http://docs.oracle.com/cd/e11882_01/java.112/e10588/chtwo.htm#babgjcaj
34 Tips&techniques bien la présence d un seul objet de type «Java Class» cette fois-ci. loadjava -u user/password@host:port:sid -r -v -f HelloWorld.jar Une petite exploration des objets du bien que le fichier JAR a été chargé puisqu un objet de type «Java Class» y est présent. Nous constatons également la présence d un deuxième objet de type «Java Resource» correspondant au fichier manifeste 2 accompagnant généralement un fichier JAR. Nous pouvons supprimer cette classe au moyen de l instruction SQL suivante: DROP JAVA CLASS ch/hegarc/helloworld/main ; Il est également possible d obtenir le même résultat en utilisant l utilitaire «dropjava» en ligne de commande: dropjava -u user/password@host:port:sid -v Main.class Dans ce cas, le fichier «Main.class» doit obligatoirement se trouver dans le répertoire courant. Si on ne dispose plus de ce fichier, la seule possibilité pour le supprimer de la base de données consiste alors à utiliser l instruction SQL précédente. Finalement, nous allons voir maintenant une troisième méthode qui consiste à charger le code Java dans la base de données au travers d un fichier JAR (Java Archive). Nous allons passer en revue les différentes variantes qui existent. Comme pour la deuxième méthode, la classe doit avoir été compilée et intégrée à un fichier JAR au préalable soit en ligne de commande avec les utilitaires «javac» et «jar» du JDK soit en passant par les services d un IDE. La première variante consiste à charger le fichier JAR de manière standard. Il suffit pour cela de remplacer dans la commande «loadjava» le nom du fichier de la classe par le nom du fichier JAR: Bien que cette solution permette de charger facilement de nombreuses classes regroupées au sein du même fichier JAR, elle présente le gros défaut de ne pas garder de lien entre celui-ci et les classes extraites. Par conséquent, il n est pas possible de supprimer l ensemble des classes d un seul coup et il faut le faire une à une. La deuxième variante consiste à charger le fichier JAR avec l option «-jarsasdbobjects». Si cette option est présente, la base de données va non seulement extraire et charger les classes du fichier JAR comme auparavant mais elle va également conserver le lien entre celui-ci et les classes extraites. loadjava -u user/password@host:port:sid -r -v -f -jarsasdbobjects HelloWorld.jar Désormais, il suffit de supprimer le fichier JAR pour que toutes ses classes soient également supprimées automatiquement. A contrario, il n est alors plus possible de supprimer une classe de manière unitaire. dropjava -u user/password@host:port:sid -v HelloWorld.jar 2 http://java.sun.com/developer/books/javaprogramming/jar/basics/manifest.html
Tips&techniques 35 Cette commande ne fonctionne que si le fichier «HelloWorld.jar» se trouve dans le répertoire courant. Si celuici n est plus disponible, il n est alors plus possible de supprimer les classes y relatif qui ont été extraites dans le schéma. Il s agira donc de conserver précieusement dans un endroit sûr tous les fichiers JAR chargés selon cette variante. La troisième et dernière variante consiste à charger le fichier JAR comme une ressource Java. Si cette option est présente, la base de données va charger le fichier JAR sans extraire ses classes. Celles-ci seront toutefois accessibles, comme nous le verrons plus loin dans cet article. utilisée, consiste à créer un «wrapper» (une enveloppe) PL/SQL qui va servir de façade pour invoquer une opération d une classe Java. Seules les méthodes statiques de la classe peuvent être enveloppées de cette manière. CREATE OR REPLACE PROCEDURE helloworldwrapper(pi_firstname IN VARCHAR2) AS LANGUAGE JAVA NAME ch.hegarc.helloworld.main.main(java.lang.string[]) ; Dès lors, nous pouvons appeler ce wrapper comme toute autre procédure PL/SQL standard. loadjava -u user/password@host:port:sid -r -v -f -jarasresource HelloWorld.jar bien que le fichier JAR a été chargé cette fois-ci comme un objet de type «Java Resource». Exécution de code Java résidant dans la base de données Maintenant que nous avons vu différentes méthodes pour charger une classe Java dans la base de données, il faut nous intéresser à la façon de l invoquer. A nouveau, nous allons passer en revue les différentes façons de procéder. Afin de rediriger la sortie standard du système Java (System.out) vers celui de la base de données, nous devons utiliser la procédure «SET_OUTPUT» du paquetage DBMS_JAVA. Celle-ci prend en paramètre la taille du buffer pour gérer la sortie. Il convient de noter que cette possibilité ne s applique pas si nous avons chargé le fichier JAR comme ressource dans la base de données. Une deuxième possibilité qui nous est offerte pour exécuter une classe Java consiste à utiliser la fonction «RUNJA- VA» du package «DBMS_JAVA». Cette fonction permet d exécuter des classes Java plus ou moins comme nous le ferions en ligne de commande de manière classique hors de la base de données. «JSERVER_SCHEMA» est un motclé qui indique que la classe doit se trouver dans le schéma de l utilisateur «JEANNERETL» dans notre cas. La classe Java invoquée peut avoir été chargée dans la base de données de manière individuelle ou au travers d un fichier JAR (standard ou jarasdbobjects). L exemple suivant ne fonctionne que si la classe Java se trouve dans un fichier JAR chargé comme une ressource (jarasresource) dans la base de données. La première possibilité, qui est certainement la plus connue et la plus
36 Tips&techniques Conclusion Pour conclure, nous venons de voir différentes manières de charger des classes Java dans la base de données Oracle et de les invoquer. Nous reviendrons prochainement dans un autre article sur des concepts plus avancés ainsi que sur des cas d utilisation de cette technologie peu connue. «JSERVER_CP/RESOURCE/SCHE- MA» est un mot-clé qui indique que le fichier JAR est une ressource du schéma «JEANNERETL» dans notre cas. Enfin, il existe une troisième et dernière possibilité pour exécuter une classe Java qui consiste à faire appel en ligne de commande à la commande «ojvmjava». Ce programme est un shell de commandes qui permet, une fois connecté à un schéma, d exécuter les classes Java qui y résident comme nous le ferions en ligne de commande de manière classique hors de la base de données. ojvmjava -user user/password@host:port:sid Contact HEG Haute école de gestion Arc Philippe Daucourt E-Mail: Philippe.Daucourt@he-arc.ch SMS > > > Studie von Oracle und PwC: Telko-CIOs wollen ihre IT 2012 besser ausnutzen 16. November 2011. In Kooperation mit PwC, einer der führenden Wirtschaftsprüfungsund Beratungsgesellschaften, hat Oracle die IT-Prioritäten von Telekommunikationsunternehmen in Europa untersucht. Der Studie zufolge entfallen bei 60 Prozent der befragten CIOs derzeit mehr als die Hälfte der Betriebskosten auf Wartung. 2012 wollen sie darauf reagieren, indem sie verstärkt auf Outsourcing und Standardisierung setzen. 88 Prozent der an der Umfrage beteiligten CIOs planen für 2012 ein Upgrade ihrer CRM-Systeme. Auf diese Weise können sie sich stärker auf strategische Anwendungen und Umsatzfaktoren, wie Portal oder Content Applications, konzentrieren. Die ganze Studie: http://www.oracle.com/us/dm/oracle-it-survey-report-401679.pdf