[JDOM] problème avec SAXBuilder

sylvain.saurel
[JDOM] problème avec SAXBuilder

Bonjour,

Mon problème est une peu particulier dans la mesure où il concerne plusieurs domaines mais étant donné que le vrai problème semble venir de la classe SAXBuilder de l'API JDOM je pense qu'il a sa place dans ce forum.
J'ai donc fait un programme JAVA qui prend en entrée un fichier XML et qui va dans un premier temps parser ce fichier, puis faire des traitements sur les données parsées avant de finalement créer un nouveau fichier XML résultat de ce traitement.

Ce programme fonctionne très bien dans la console. Pour l'application que je développe j'ai besoin de passer par php sur un serveur Apache2 donc pour utiliser le programme JAVA.

J'ai donc dans mon programme PHP utilisé la fonction system("java monProgramme donnees.xml", $retval); qui exécute la commande passée en paramètre dans un shell. J'ai bien vérifié que l'utilisateur sur lequel tourne le serveur Apache2 a les droits nécessaires, et que le CLASSPATH et le PATH soient bien configurés. D'ailleurs lorsque j'éxécute mon programme JAVA en mode console en étant loggué sous cet utilisateur tout marche bien.

Et là, bizarrement quand j'exécute le programme, il y a un problème. Après pas mal de temps de recherche je suis arrivé à isoler ce qui empêchait le programme de fonctionner et apparemment cela viendrait de la ligne suivante dans le programme JAVA :

SAXBuilder sxb = new SAXBuilder();

J'ai réduit au maximum mon programme pour ne laisser plus que ça dans la classe principale du programme :

public ParseurDOM()
    {
        SAXBuilder sxb = new SAXBuilder();
        System.out.println("Test");
    }

En exécutant le programme JAVA depuis PHP avec ça dans la classe principale, j'ai un retour d'exécution à 1 qui indique qu'il y a une erreur (qui ne peut donc venir que du constructeur SAXBuilder) et l'affichage de la ligne "Test" ne se fait pas.

En enlevant l'appel au constructeur SAXBuilder(), j'ai bien l'affichage de la ligne "Test". Le problème se situe donc dans le constructeur SAXBuilder().

J'ai donc été voir dans les sources de JDOM dans la classe SAXBuilder et je ne vois rien de spécial en fait. Lors de l'instanciation, il y a juste une instanciation de la classe DefaultJDOMFactory dont le constructeur ne fait rien !

Donc, je ne vois vraiment pas d'où ça peut venir à ce niveau là, je pensais à un problème de localisation du driver SAX utilisé par SAXBuilder mais même en changeant et en mettant dans le constructeur SAXBuilder() un driver SAX valide : org.apache.xerces.parsers.SAXParser par exemple (et en modifiant le classpath), le problème reste le même.

J'ai même tenté d'utiliser d'autres API du même genre comme DOM4J ou autres mais ça bloque toujours au même niveau lorsque l'on crée une instance de la classe cherchant les drivers SAX apparemment.

Quelqu'un aurait une idée de ce que je peux faire ? Peut-être modifier des options dans Apache2 (je ne vois pas trop ce que je peux modifier de plus en fait)? Modifier un chemin d'accès ? Ou peut être cela ne peut pas se faire et ça ne marchera pas ?

Merci d'avance de votre aide.

fredericmazue

bonjour,

Voilà une question précise et détaillé comme je les aime :)

Tu as bien dit et redit que tu avais veillé au classpath, mais je pense que c'est un problème de classpath quand même :twisted:

D'abord parce que ce que tu décris est symptomatique du classpath, ensuite parce que si j'ai bien compris tu lances la JVM depuis Php.
Qui te dit que Php passe tout l'environnement à la JVM dans ce cas ?

As tu essayé system("java -cp LE_CLASSPATH monProgramme donnees.xml", $retval);

sylvain.saurel

Effectivement, je ne sais pas trop comment se comporte la JVM quand PHP est utilisé pour l'exécuter.

Je viens d'essayer en précisant le classpath vers le jar de l'API JDOM dans le ligne de commande et le résultat est le même.

Mais en même temps le fait que l'utilisateur sur lequel tourne Apache puisse exécuter sans problème le programme JAVA en mode console me fait penser que le problème vient pas de là forcément mais bon je suis pas sur non plus.

fredericmazue

tu nous la montres cette ligne de commande ?

Et ce jar, où est-il ?

Et peut être que le problème s'est déplacé. La JVM trouvera SAX mais pas une autre classe ?

sylvain.saurel

En fait, tu as raison je pense. C'est bien un problème de CLASSPATH mais d'autres jar qui manquent je pense.

Je viens de comprendre (avec un peu de retard certes) que pour utiliser JDOM, il ne fallait pas juste utiliser le jar mais lancer le programme ANT notamment avec d'autres classes.

Dans le dossier JDOM, il y a un script shell qui permet de faire ces lancements (que j'ai adapté avec les chemins vers mes jar)


#!/bin/sh
echo "JDOM Build System"
echo "-------------------"
LOCALCLASSPATH=/usr/lib/j2sdk1.5-sun/lib/tools.jar:/usr/lib/j2sdk1.5-sun/lib/dev.jar:./lib/ant.jar:./lib/xml-apis.jar:./lib/xerces.jar
ANT_HOME=./lib
/usr/lib/j2sdk1.5-sun/bin/java -Dant.home=$ANT_HOME -classpath $LOCALCLASSPATH org.apache.tools.ant.Main $*

Il y a cependant un problème avec l'archive dev.jar qui d'après le readme de JDOM devrait se trouver dans le dossier /usr/lib/j2sdk1.5-sun/lib/ mais qui n'y est pas chez moi. Je vais essayer de la trouver sur internet et je vous tiens au courant.

fredericmazue

tu ne t'égare pas un peu là ? Le programme Java console autonome marchait n'est-ce pas ?

sylvain.saurel

fredericmazue wrote:
tu ne t'égare pas un peu là ? Le programme Java console autonome marchait n'est-ce pas ?

Le programme java autonome marche et sans avoir eu à utiliser ce script shell mais étant donné que je ne sais plus trop quoi faire je me disais que ça pouvait peut être venir de là.
Mais c'est sur que si ça marche sans avoir utilisé ce script en console, ça devrait marcher via mon programme php sans avoir à l'utiliser.

J'ai essayé cette ligne dans le script PHP :
system("/usr/bin/java Utilitaire ".$fichier." -cp /usr/share/java/jdom.jar", $retval);

et le résultat est toujours le même. L'exécution me renvoie toujours 1 en retour ce qui veut dire qu'il ya un problème.
Le problème étant de localiser cette erreur mais SAXBuilder ne renvoie aucune indication sur cette erreur.

sylvain.saurel

Voici les deux programmes que j'utilises :

- le programme java (réduit au minimum ici)

import org.jdom.*;
import org.jdom.input.*;

public class JDOM3
{
static org.jdom.Document document;
static Element racine;

public static void main(String[] args)
{
//On crée une instance de SAXBuilder
try{

SAXBuilder sxb = new SAXBuilder(); // l'erreur vient de l'appel a ce constructeur puisque quand je l'enlève cela se passe normalement
System.out.println("test");


}catch(Exception e){

e.printStackTrace();
}

}
}

- le programme php

<?php

$line = system("/usr/bin/java -cp /usr/share/java/jdom.jar JDOM3", $retval);
echo"Statut : ".$retval;

?>

- Et la librairie JDOM : http://www.jdom.org/dist/binary/jdom-1.0.zip
Il suffit de prendre l'archive jdom.jar se trouvant dans le dossier build une fois l'archive zip décompressée. Et ensuite d'ajouter au classpath jdom.jar

Si vous avez le temps ou si quelqu'un a le temps d'essayer de faire tourner ça sur son serveur parce que là je suis à cours d'idées vraiment.

Merci d'avance.

fredericmazue

> csystem("/usr/bin/java Utilitaire ".$fichier." -
> cp /usr/share/java/jdom.jar", $retval);

Hé...

java -cp . LaClasse et java LaClasse -cp . ne sont pas identiques.
Le premier fonctionne, pas le second...

> SAXBuilder sxb = new SAXBuilder(); // l'erreur vient de l'appel a ce
> constructeur
> que là je suis à cours d'idées vraiment.

Cet appel au constructeur ne peut échouer ... si la classe est trouvée.
Vraiment tu as un problème de classpath. Selon moi c'est aussi sûr que certain.

Tu nous dit "// l'erreur vient de l'appel a ce constructeur puisque quand je l'enlève "
Certes. Et pourquoi ne pas écrire ton code ainsi ?

try {
Appel au constructeur
}
catch(Exception) {
e.printStackTrace_dans_un_fichier_ave_les_droits__en_ecriture;
}

Comme ça tu n'aurais plus le moindre doute et tu chercherais et finirais par trouver pourquoi ton classpath n'est pas valide

sylvain.saurel

Depuis hier, je suis arrivé à récupérer le message d'erreur en bidouillant un peu :

import java.io.*;
import org.jdom.*;
import org.jdom.input.*;

class TestSAX{

TestSAX()
{

}

void instanciateSAXBuilder()
{
//On crée une instance de SAXBuilder
try{
SAXBuilder sxb = new SAXBuilder();

System.out.println("Constructeur de SAX");


}catch(Throwable e){

e.printStackTrace();
}
}

}

public class Test {
public static void main (String[] args) {

PrintStream ps = null;

try{

ps = new PrintStream("./test.txt");

}catch(Exception e){

e.printStackTrace();

}

System.setOut(ps);
System.setErr(ps);
System.out.println("test");

try {
System.out.println("Step 1");
TestSAX ts = new TestSAX();
System.out.println("Step 2");
ts.instanciateSAXBuilder();
System.out.println("Step 3");
} catch (Throwable t) {
System.out.println("FAILED");
t.printStackTrace();
}


}

}

Donc en fait l'erreur se situe bien au niveau de la classe SAXBuilder. Dans le fichier test.txt, j'obtiens ça :

test
Step 1
FAILED
java.lang.NoClassDefFoundError: org/jdom/input/SAXBuilder
at Test.main(Test.java:51)

Donc effectivement, au niveau de l'exécution par PHP le CLASSPATH ne semble pas être bien reconnu.
Et même en passant le classpath avec -cp (c'est une erreur que j'avais fait dans le précédent post) à java, cela reste pareil.

J'ai essayé de faire un autre truc pour vérifier le classpath lorsque php exécute le programme. J'ai tenté de compiler le programme Test.java depuis php avec la commande javac.

Avec ça :

$line = system("/usr/bin/javac Test.java", $retval);

Une erreur se produit et cela ne compile pas, confirmant que le CLASSPATH n'est pas bon.

En revanche, lorsque je rajoute le classpath vers jdom à la commande javac là ça compile normalement et après exécution du programme php, j'ai l'exécutable Test qui est crée normalement.

$line = system("/usr/bin/javac -cp /usr/share/java/jdom.jar Test.java", $retval);

Donc, c'est bizarre qu'il accepte bien le classpath passé en paramètre quand on utilise javac mais qu'avec java cela ne passe plus.

fredericmazue

>java.lang.NoClassDefFoundError: org/jdom/input/SAXBuilder
> Donc effectivement, au niveau de l'exécution par PHP le CLASSPATH ne
> semble pas être bien
> reconnu.

C'est incontestable.

> Donc, c'est bizarre qu'il accepte bien le classpath passé en paramètre
> quand on utilise javac mais

Ca n'a pas de sens. Javac est écrit en Java...

Pour moi c'est clair, tu as une petite merdouille qui fait que tu ne passes pas le bon classpath. Le bug typique qu'on met des heures à trouver. Maintenant que le problème est clairement et incontestablement identifié, tu vas forcément trouver.

Cela dit Java et son classpath... :evil: Vive Python :P

Bon courage, la solution est proche

sylvain.saurel

Yesssssssssssssssss !

Ca marche enfin, après 2 jours et demi de recherche lol
Il fallait rajouter le CLASSPATH actuel dans la modification du
CLASSPATH dans l'appel à java car lorsque l'on met l'option -cp à
java il écrase le CLASSPATH actuel pour ne tenir compte que du nouveau
qui est soumis.

J'ai donc fait la ligne suivante :

system("/usr/bin/java -cp \$CLASSPATH:/usr/share/java/jdom.jar Test"
$retval);

et enfin ça marche ! Merci à toi de m'avoir aidé en tous cas :)

fredericmazue

> Il fallait rajouter le CLASSPATH actuel dans la modification du
> CLASSPATH dans l'appel à java car lorsque l'on met l'option -cp à
> java il écrase le CLASSPATH actuel pour ne tenir compte que du nouveau
> qui est soumis.

Ben oui, j'ai failli te le dire. Mais comme tu étais affirmatif que seule l'absence de la classe SaxBuilder levait l'exception, je ne l'ai pas dit.
Donc le problème s'était bien déplacé comme je te l'avais suggéré dans un post précédent.

> Merci à toi de m'avoir aidé en tous cas

De rien. C'était avec plaisir. je suis heureux que ton problème soit solutionné