[Résolu] EJB : Problème méthode findAll() avec Jonas

mixouille
[Résolu] EJB : Problème méthode findAll() avec Jonas

Bonjour,

J'ai un problème pour utiliser la méthode findAll() d'un EJB entité (CMP), et d'ailleurs également pour toute méthode finder personnalisée. Je tiens à préciser tout de suite que je suis débutant en matière d'EJB.

J'utilise Jonas 4.7.4 comme serveur, Oracle 9i comme base de données, et XDoclet 1.2.3 pour la génération du code.

Voici un extrait de mon fichier ejb-jar.xml :

<!-- Entity Beans -->
<entity id="ContainerManagedEntity_TestCmp">
   <description><![CDATA[<!-- begin-xdoclet-definition -->]]></description>

   <ejb-name>TestCmp</ejb-name>

   <home>com.sicc.cmp.TestCmpHome</home>
   <remote>com.sicc.cmp.TestCmp</remote>
   <local-home>com.sicc.cmp.TestCmpLocalHome</local-home>
   <local>com.sicc.cmp.TestCmpLocal</local>

   <ejb-class>com.sicc.cmp.TestCmpCMP</ejb-class>
   <persistence-type>Container</persistence-type>
   <prim-key-class>java.lang.Integer</prim-key-class>
   <reentrant>false</reentrant>
   <cmp-version>2.x</cmp-version>
   <abstract-schema-name>TestCmpSCHEMA</abstract-schema-name>
   <cmp-field id="CMPAttribute_1">
      <description><![CDATA[<!-- begin-user-doc --> CMP Field id_trt Returns the id_trt]]></description>
      <field-name>id_trt</field-name>
   </cmp-field>
   <cmp-field id="CMPAttribute_2">
      <description><![CDATA[<!-- begin-user-doc --> CMP Field trt_libelle Returns the trt_libelle]]></description>
      <field-name>trt_libelle</field-name>
   </cmp-field>
   <cmp-field id="CMPAttribute_3">
      <description><![CDATA[<!-- begin-user-doc --> CMP Field trt_classe Returns the trt_classe]]></description>
      <field-name>trt_classe</field-name>
   </cmp-field>
   <cmp-field id="CMPAttribute_4">
      <description><![CDATA[<!-- begin-user-doc --> CMP Field trt_creepar Returns the trt_creepar]]></description>
      <field-name>trt_creepar</field-name>
   </cmp-field>
   <cmp-field id="CMPAttribute_5">
      <description><![CDATA[<!-- begin-user-doc --> CMP Field trt_modifpar Returns the trt_modifpar]]></description>
      <field-name>trt_modifpar</field-name>
   </cmp-field>
   <cmp-field id="CMPAttribute_6">
      <description><![CDATA[<!-- begin-user-doc --> CMP Field trt_dtcreation Returns the trt_dtcreation]]></description>
      <field-name>trt_dtcreation</field-name>
   </cmp-field>
   <cmp-field id="CMPAttribute_7">
      <description><![CDATA[<!-- begin-user-doc --> CMP Field trt_dtmodif Returns the trt_dtmodif]]></description>
      <field-name>trt_dtmodif</field-name>
   </cmp-field>
   <cmp-field id="CMPAttribute_8">
      <description><![CDATA[<!-- begin-user-doc --> CMP Field trt_actif Returns the trt_actif]]></description>
      <field-name>trt_actif</field-name>
   </cmp-field>
    <primkey-field>id_trt</primkey-field>

   <query>
      <query-method>
         <method-name>findAll</method-name>
         <method-params>
         </method-params>
      </query-method>
      <ejb-ql><![CDATA[SELECT OBJECT(a) FROM TestCmpSCHEMA as a]]></ejb-ql>
      </query>
<!-- Write a file named ejb-finders-TestCmpBean.xml if you want to define extra finders. -->
</entity>

Lorsque je veux appeler cette méthode, par un code du style :

	    // Récupération d'une référence à l'interface locale
	    TestCmpHome home = null;
	    try {
	      home = (TestCmpHome)PortableRemoteObject.narrow(initialContext.lookup("TestCmp"), TestCmpHome.class);
	     
	    } catch (Exception e) {
	      System.err.println( "Impossible de trouver TestCmpHome : " + e);
	      System.exit(2);
	    }

	    // Création d'un objet de même type que l'interafce distante
	    // et appel de la fonction sayHello()
	    TestCmp myTestCmp = null;
	    String returnString = "";
	    Collection lstTrt = null;
	    
	    try {
	    	lstTrt = home.findAll();
	    	if (lstTrt.size() > 0) {
	    		Iterator iter = lstTrt.iterator();
	    		myTestCmp = (TestCmp)iter.next();
	    		returnString = myTestCmp.getTrt_libelle();
	    	} else {
	    		returnString = "RIEN";
	    	}
	    	

	      Log.ajouter(Log.NIVEAU_DEBUG, NOM_PACKAGE, NOM_CLASSE, NOM_METHODE, returnString);

	    } catch (Exception e) {
	      System.err.println("Impossible de créer le bean : " + e);
	      System.exit(2);
	    }

mon serveur Jonas tombe, et j'obtiens les messages d'erreur suivants :

2006-07-26 17:56:13,671 : JOnASTestCmp2046519629Bean.ejbfindAll : Problem during the evaluation of findAll
Nested Exception
Nested Exception
java.sql.SQLException: ORA-00933: SQL command not properly ended

	at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:125)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:305)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:272)
	at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:623)
	at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:181)
	at oracle.jdbc.driver.T4CPreparedStatement.execute_for_describe(T4CPreparedStatement.java:420)
	at oracle.jdbc.driver.OracleStatement.execute_maybe_describe(OracleStatement.java:896)
	at oracle.jdbc.driver.T4CPreparedStatement.execute_maybe_describe(T4CPreparedStatement.java:452)
	at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:986)
	at oracle.jdbc.driver.OracleStatement.doScrollExecuteCommon(OracleStatement.java:3763)
	at oracle.jdbc.driver.OraclePreparedStatement.doScrollPstmtExecuteUpdate(OraclePreparedStatement.java:8829)
	at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:2886)
	at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:2929)
	at org.objectweb.jonas.dbm.JStatement.executeQuery(JStatement.java:335)
	at org.objectweb.medor.datasource.rdb.lib.JDBCWrapper.fetchData(JDBCWrapper.java:158)
	at org.objectweb.medor.eval.lib.MedorEvaluator.evaluate(MedorEvaluator.java:145)
	at org.objectweb.jonas_ejb.container.jorm.MedorFactory.evaluate(MedorFactory.java:245)
	at org.objectweb.jonas_gen.com.sicc.cmp.JOnASTestCmp2046519629Bean.ejbfindAll(JOnASTestCmp2046519629Bean.java:557)
	at org.objectweb.jonas_gen.com.sicc.cmp.JOnASTestCmp2046519629Home.findAll(JOnASTestCmp2046519629Home.java:332)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:324)
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:261)
	at org.objectweb.carol.rmi.jrmp.server.JUnicastServerRef.dispatch(JUnicastServerRef.java:143)
	at sun.rmi.transport.Transport$1.run(Transport.java:148)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:144)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:460)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:701)
	at java.lang.Thread.run(Thread.java:534)
2006-07-26 17:56:13,671 : JStatement.forceClose : Statements should be closed explicitly.
Impossible de créer le bean : javax.ejb.FinderException: An error occured during the evaluation of the findAll request:Nested Exception

Je précise pour finir que je n'ai en revanche aucun problème pour utiliser un findByPrimaryKey().

Quelqu'un a-t-il idée de l'origine du problème ? J'ai cherché dans tous les sens sur le net, mais je ne trouve pas de problème semblable.

Merci beaucoup d'avance !

mixouille

Ca y est, j'ai trouvé les réponses à toutes mes questions !

Premièrement, pour logger les requêtes sql émises par Jonas, il existe l'excellent outil p6spy, qui, en plus, est livré avec la version 4.7.4 (et probablement d'autres) de Jonas.
La configuration est très simple et expliquée ici : http://www.p6spy.com/documentation/install.htm

Grâce à cet outil, j'ai pu voir la requête problématique générée :
SELECT SICC_ADMIN.TS_WF_TRAITETEMPO_0.ID_TRT FROM SICC_ADMIN.TS_WF_TRAITETEMPO SICC_ADMIN.TS_WF_TRAITETEMPO_0

Vous voyez le problème ? En fait Jonas ne voit visiblement pas que "SICC_ADMIN" est le schéma de la table, et préfixe donc l'alias TS_WF_TRAITETEMPO_0 avec, ce qui est évidemment interdit. La requête devrait être :
SELECT TS_WF_TRAITETEMPO_0.ID_TRT FROM SICC_ADMIN.TS_WF_TRAITETEMPO TS_WF_TRAITETEMPO_0

Pour régler le problème, j'ai trouvé 2 solutions, dans XDoclet :

1 - Dans la classe BiduleBean.java, supprimer le schéma dans les commentaires suivants :

 *  @ejb.persistence 
*   table-name="SICC_ADMIN.TS_WF_TRAITETEMPO"

* @jonas.jdbc-mapping jndi-name="DefaultDS" automatic-pk="false" jdbc-table-name="SICC_ADMIN.TS_WF_TRAITETEMPO"
Puis relancer XDoclet. Les classes et descripteurs sont regénérés correctement.

2 - Si, comme moi, vous utilisez l'assistant XDoclet de création d'EJB CMP dans Eclipse, lors de l'étape de sélection de la table et des champs, supprimez le schéma dans le nom de la table avant de valider l'étape.

Voilà, j'espère que cette explication aidera ceux qui seront comme moi confrontés à ce bug (parce que ca ressemble à un bug, quand même) de Jonas.