Java / PHP Bridge

Cette page a été rédigée il y a fort fort longtemps, et n'a pas tellement été mise à jour.

 

Vous savez, moi je ne crois pas qu'il y ait de bonne ou de mauvaise page. Moi, si je devais résumer mon wiki aujourd'hui avec vous, je dirais que c'est d'abord des rencontres. Des gens qui m'ont tendu la main, peut-être à un moment où je ne pouvais pas, où j'étais seul chez moi. Et c'est assez curieux de se dire que les hasards, les rencontres forgent une destinée... Parce que quand on a le goût de la chose, quand on a le goût de la chose bien faite, le beau geste, parfois on ne trouve pas l'interlocuteur en face je dirais, le miroir qui vous aide à avancer. Alors ça n'est pas mon cas, comme je disais là, puisque moi au contraire, j'ai pu ; et je dis merci au wiki, je lui dis merci, je chante le wiki, je danse le wiki... je ne suis qu'amour ! Et finalement, quand des gens me disent « Mais comment fais-tu pour avoir cette humanité ? », je leur réponds très simplement que c'est ce goût de l'amour, ce goût donc qui m'a poussé aujourd'hui à entreprendre une construction logicielle... mais demain qui sait ? Peut-être simplement à me mettre au service de la communauté, à faire le don, le don de soi.

Le PHP/Java Bridge de sourceforge.net permet d’intégrer Java et PHP dans les deux sens : il permet d’appeler des classes Java depuis PHP, mais aussi d’appeler des scripts PHP depuis Java. Pour ce sens, le bridge fournit même deux techniques : appel en CGI, ou via la nouvelle technique d’appel de script de Java 6, référencée sous la JSR-223. On notera que le pont peut aussi fonctionner entre PHP et .NET ou Mono.

Ces notes ont servi de base pour la rédaction d’un article paru le numéro 6/2008 de PHP Solutions de novembre 2008.

Installation

L’environnement que je décris ci-dessous n’est qu’un exemple d’environnement compatible avec la version 5.2 du pont. Il a été testé sous Linux Ubuntu 8.04 et sous Window XP SP2 et SP3.

Environnement PHP :

  • Apache Web Server 2.2

  • PHP 5.2

  • allow_url_include = On dans php.ini

Environnement Java :

  • Java JDK 6

  • Apache Tomcat 6.0

Ensuite, il faut déployer JavaBridge.war dans Tomcat. Tomcat étant par défaut en mode de déploiement automatique, le déploiement se fait par copie du fichier dans son répertoire webapps/.

Intégration par CGI

On ne peut pas réellement parler d’intégration. Cette technique permet surtout de déployer des pages PHP dans Tomcat, sans avoir recours à Apache ou IIS.

JavaPhpBridgeCgi.png

Java Scripting API

La Java Scripting API, parfois connue sous le nom de sa spécification, JSR-223, définit une API permettant d’utiliser des langages de script dans une application Java. Le langage JavaScript est nativement supporté par la machine virtuelle qui intègre l’interpréteur Rhino. Le pont peut servir d’interpreteur PHP pour cette API.

Il fournit cinq modes d’intégration :

  • php simple, qui exécute simplement un script,

   manager.getEngineByName("php")
  • php interactif, qui exécute une série de lignes de code et qui permet de récupérer un résultat dans Java,

   manager.getEngineByName("php-interactive")
  • php invocable, qui permet d’appeler une fonction PHP et de récupérer son retour,

   manager.getEngineByName("php-invocable")
  • un mode Web, qui permet de partager un contexte et des informations de session,

  • un mode Web invocable, qui fait la synthèse de deux derniers (c’est mon préféré).

 // Affichage du titre
 out.println ("Essai de JSR-223 - mode Web invocable
");
 // Récupération de l'interpréteur de PHP via la méthode de fabrique
 ScriptEngine engine = EngineFactory.getInvocablePhpScriptEngine (this, application, request, response);
 // Connexion des sorties Java et PHP
 engine.getContext ().setWriter (out);
 // Déclaration de la fonction hello
 engine.eval ("<?php function hello ($who) {return 'Hello '.$who;}; ?>");
 // Appel de la fonction hello et affichage du résultat
 out.println (((Invocable) engine).invokeFunction ("hello", new Object[] {"world"}));
 // Réinitialisation de l'interpréteur
 engine.eval ((java.io.Reader)null);

Pont PHP vers Java

Appeler une classe standard

 <?php
   // Fichier des fonctions et classes PHP du pont
   require_once ("link:http://localhost:8080/JavaBridge/java/Java.inc[http://localhost:8080/JavaBridge/java/Java.inc]");

   // Instanciation de la classe Java StringBuilder via la classe PHP Java
   $buf=new Java ("java.lang.StringBuilder");
   // Appel de la méthode append sur l'objet Java StringBuilder
   $buf->append ("Hello");
   $buf->append (" ");
   $buf->append ("World");
   // Appel de la méthode toString sur l'objet Java StringBuilder et affichage du résultat
   echo ($buf->toString ());
 ?>

A chaque appel de la page, une requête est envoyée vers Tomcat, à la servlet PhpJavaServlet de l’application JavaBridge, puis les échanges se font ensuite sur un port spécifique (entre 9267 et 9367)

JavaPhpBridgePhpJavaServlet.png

Appeler une classe personnalisée

Pour que PHP puisse utiliser des classes métier, il faut en plus que l’application puisse avoir accès aux archives jar qui contiennent leurs définitions. L’accès peut être donné côté PHP, par la fonction java_autoload, ou côté Java. Si une seule archive est utilisée, la première solution est plus pratique, et si plusieurs archives sont nécessaires, ce qui est le cas le plus fréquent, il est plus pratique de gérer leur mise à disposition du côté de Java.

 <?php
   require_once ("link:http://localhost:8080/JavaBridge/java/Java.inc[http://localhost:8080/JavaBridge/java/Java.inc]");
   // Chargement de l'archive java copiée localement
   java_autoload ("java/university.jar") ;

   // Instanciation d'un objet Course
   $course=new Java ("fr.sewatech.university.model.Course", "mm-uml", "Analyse et conception avec UML");
   // Affichage du résultat
   echo ($course->toString ());
 ?>

Appeler un bean Spring

En effet, depuis plusieurs années, de nombreuses applications Java ont été développées sur ce type de framework. Que ce soit Spring ou ses concurrents, ils ont pour point commun de gérer des composants, en les instanciant et en les mettant à disposition via des noms logiques plutôt que par des noms de classes.

Pour appeler des services métier intégrés à Spring, notre application PHP doit d’abord accéder au contexte Spring avant d’accéder aux beans.

 <?php
   require_once("link:http://localhost:8080/UniBridge/java/Java.inc[http://localhost:8080/UniBridge/java/Java.inc]");

   // Instanciation du contexte applicatif de Spring paramétré dans le fichier application-context.xml
   $ctx = new Java(
       "org.springframework.context.support.ClassPathXmlApplicationContext",
       "application-context.xml");
   // Demande d'une référence au bean courseService inscrit dans Spring
   $service = $ctx->getBean("courseService");
   // Utilisation du bean
   $course=$service->findById(1);
   echo ($course->toString());
 ?>

Il faut toutefois faire attention à la gestion des librairies dépendantes. En effet, lorsque nous utilisons des composants métier intégrés à Spring, nous devons accéder aux archives métier et à des archives techniques (spring.jar, commons-beanutils.jar, commons-collections.jar,…​). Nous avons trois possibilités pour rendre celles-ci accessibles :

  • les ajouter à la fonction java_autoload, ce qui peut être fastidieux,

  • les ajouter au répertoire lib/ de Tomcat, ce qui les rend accessibles à toutes les applications déployées, mais peut provoquer des conflits avec des versions utilisées dans d’autres applications,

  • les ajouter au répertoire WEB-INF/lib de l’application JavaBridge, ce qui constitue la meilleure option si une seule application Java est utilisée depuis PHP.

Pour éviter les risques de conflit lorsque plusieurs applications Java sont utilisées, on peut mettre en place une quatrième technique, en intégrant le contenu de JavaBridge à chaque application Java. Chacune embarque donc son propre pont ; de plus, toutes les classes Java nécessaires à PHP sont déjà chargées par le pont, ce qui nous dispense d’appeler la fonction java_autoload. Seul le require_once doit être adapté pour charger celui de l’application Java accédée. Cette technique a été utilisée dans l’exemple précédent, ce qui explique l’absence de la fonction java_autoload.

Pour ajouter le pont à une application, il faut :

  • ajouter les fichiers JavaBridge.jar et php-servlet.jar, dans le répertoire WEB_INF/lib de l’application,

  • ajouter le répertoire java et son contenu à la racine de l’application,

  • prendre, dans le fichier WEB-INF/web.xml, les deux portions qui concernent la servlet PhpJavaServlet (éléments <servlet> et <servlet-mapping>) et les ajouter dans le fichier équivalent de notre application.