Affichage des articles dont le libellé est j2ee. Afficher tous les articles
Affichage des articles dont le libellé est j2ee. Afficher tous les articles

jeudi 18 juin 2009

Utiliser les Advanced Queue en Java sur Oracle !

Après 3 jours de nuits blanches à chercher sur des milliers de sites pour intégrer les queues et JMS (Java Message Service) sur mon serveur Oracle 9i, j'ai enfin réussi à faire ce que je voulais... ouf! :)

Voici ce que je cherche à faire :
J'ai une base Oracle 9i, lorsqu'un enregistrement dans une table (par exemple la table Banque) est modifié/créé, je veux que mon application Java soit directement mise au courant lorsque l'opération est effectuée sur la base de données.

Pour "mettre au courant" mon application, on utilise un service très pratique introduit dans J2EE : JMS (Java Message Service). Comme son nom l'indique, c'est un service de message. Les messages sont produits dans une Queue et lus par les destinataires à partir de celle çi.

La base Oracle, à la modification/création d'un élément de la table Banque, produira un message JMS qui sera capté par mon application Java. Oui vous avez bien lus : Oracle est capable (je crois depuis la version 8) de produire des messages JMS : ce système sur Oracle s'appelle Advanced Queue (AQ).

Pour réaliser ce tour de magie, on définit tout d'abord un trigger sur la table (trigger en update, create,delete etc...). Ce trigger appellera une procédure stockée qui se chargera d'écrire et d'envoyer un message JMS. Coté Java, on aura besoin de se connecter à la queue Oracle et d'être prévenu lorsqu'un message arrive pour le traiter ensuite.

Ca parait très simple sur le papier, et ça l'est en pratique à condition que ça marche du premier coup qui n'a pas été mon cas !! Les docs et tutorials Oracles sur la toile sont assez nombreux et simples mais malheureusement (je peux citer par exemple http://gbowyer.freeshell.org/oracle-aq.html), en cas d'erreur (j'avais une exception que je ne comprenais pas d'où elle venait) on est vite paumé pour trouver une solution. Heureusement, à travers cet article et mon expérience acquise, je pense que je pourrai en aider certains !

Les pré requis nécessaires :
  • Une base Oracle 8 au minimum installée sur un serveur. Cet article se base sur la 9i
  • Les outils clients d'Oracle pour votre base (ces outils intégrent les drivers JDBC et le nécessaire pour lire les messages Oracle) installés sur votre machine de développement. ATTENTION : je tiens à avertir, car j'ai eu le cas, comme j'avais la version 9i, ça me paraissais logique d'installer les outils clients pour la 9i. Ben non ! j'ai pas du tout réussi à faire marcher mon programmes avec les librairies pour la 9i !! J'ai mis un jour et demi pour m'en rendre compte que ça venait des bibliothèques d'Oracle ! :( (j'avais des exceptions du type AbstractError à la connexion à Oracle). J'ai téléchargé les outils pour la version 10g (pas essayé sur la version 11g), et ça marche nickel même sur la base 9i !! (Peut être téléchargé à l'adresse : http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10201winsoft.html)
  • Un environnement de développement J2EE (J2EE 5 conseillé), j'utilise pour ma part RAD 7 (Rational Application Developper)
  • Un projet J2EE avec Spring de configuré (pas la peine de présenter Spring ? ...)
Passons à la mise en pratique :

1. Création de la queue dans Oracle

Pour commencer, on va s'attacher à créer la queue sur la base Oracle.

Connectez vous sur la base avec SQL*Plus en tant que SysDBA.

Il faut créer un utilisateur qui aura accès aux queues (et pourra écrire dedans). Une fois l'utilisateur créé, il faut lui donner les droits suivants : DBMS_AQ et DBMS_AQADM
GRANT EXECUTE ON DBMS_AQ TO MON_USER;
GRANT EXECUTE ON DBMS_AQADM TO MON_USER;
où MON_USER est le nom de l'utilisateur créé


Pour créer la queue, il suffit de lancer la commande suivante :
EXEC dbms_aqadm.create_queue_table(queue_table=>'content_queue', queue_payload_type=>'sys.aq$_jms_text_message', multiple_consumers=>TRUE);
EXEC dbms_aqadm.create_queue(queue_name=>'cnt_queue', queue_table=>'content_queue');
EXEC dbms_aqadm.start_queue(queue_name=>'cnt_queue');
commit;


cnt_queue est le nom de la queue à créer.
content_queue le nom de la table où Oracle va stocker les données.
queue_payload_type est le type des données dans les messages. Ici j'ai mis texte.
Je vous laisse le soin de lire par exemple http://hell.org.ua/Docs/oreilly/oracle/bipack/ch05_05.htm pour la liste complète des paramètres.

2. Création de la procédure et du trigger sur une table

Je le rappelle, le but de la procédure est d'écrire un message JMS dans la queue créée plus haut. Cette procédure sera appelée par un trigger sur la table.

Voici comment créer la procédure, toujours à partir de SQL*Plus :
CREATE OR REPLACE PROCEDURE PROC_CACHE_CTRL_NOTIFICATION(TABLE_NAME IN VARCHAR) AS
msg SYS.AQ$_JMS_TEXT_MESSAGE;
queue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
msg_props DBMS_AQ.MESSAGE_PROPERTIES_T;
msg_id RAW(16);
no_consumers_error EXCEPTION;
PRAGMA EXCEPTION_INIT(no_consumers_error, -24033);
BEGIN
-- Ensure what is sent will be a JMS message
msg := SYS.AQ$_JMS_TEXT_MESSAGE.CONSTRUCT();

msg.set_text('TABLE_NAME=' || TABLE_NAME);
DBMS_AQ.ENQUEUE( queue_name => 'cnt_queue'
, enqueue_options => queue_options
, message_properties => msg_props
, payload => msg
, msgid => msg_id);
-- Without the following, the procedure will die if noone
-- Is listening for cache control
EXCEPTION
WHEN no_consumers_error
THEN
-- Output it in case, but otherwise swallow
DBMS_OUTPUT.PUT_LINE('No interested parties are listening to cache-control messages');
END;


Cette petite procédure va écrire un message texte TABLE_NAME=la valeur passée en paramètre de la procèdure. Je vous laisse le loisir de personnaliser un peu cette procédure. Notez l'utilisation de DBMS_AQ.ENQUEUE pour poster un message.

Il faut créer désormais le trigger : sur la table Banque par exemple :
CREATE OR REPLACE TRIGGER TRGR_BANQUE
AFTER DELETE OR INSERT OR UPDATE
ON BANQUE
CALL PROC_CACHE_CTRL_NOTIFICATION('BANQUE');


3. Création des classes Java pour la connexion et réception des messages

Ouvrir votre projet J2EE avec Spring, on va créer trois classes pour la reception des messages.

Mais pour commencer, il faut modifier le classpath (Chemin de génération JAVA sous Eclipse ou RAD) :
  • Ajouter les jars aqapi13.jar et jmscommon.jar. Ces jars ce situent dans le répertoire rdbms/jlib du répertoire d'installation des outils clients d'Oracle (cf. plus haut). Si elles n'y sont pas, c'est que vous avez pas tous installé....
  • Ajouter le jar ojdbc14.jar. Ce jar est dans le répertoire jdbc/lib d'Oracle
Créer la classe de création de la connexion à la base Oracle :

package trigger;

import javax.jms.ConnectionFactory;
import oracle.jms.AQjmsFactory;

public class OracleAQTopicConnectionFactory
{

public ConnectionFactory createConnectionFactory() throws Exception
{
String url="jdbc:oracle:thin:MON_USER/MON_MDP@MON_SERVER:MON_PORT:MON_SID";

ConnectionFactory c= AQjmsFactory.getTopicConnectionFactory(url,null);
return c;
}
}

où MON_USER et MON_MDP sont respectivement le login et mot de passe de l'utilisateur ayant accés aux queues sur la base Oracle (voir plus haut)
MON_SERVEUR, MON_PORT sont le nom du serveur et le port pour se connecter à la base
MON_SID : le nom de l'instance Oracle

Note importante : vous remarquez que j'ai mis le login et mot de passe dans l'URL de connexion, je sais pas pourquoi, la connexion ne MARCHERA PAS si ces deux infos ne sont pas présentes ... (j'ai mis 3h pour m'en apercevoir !)

La deuxième classe à créer est une classe de connexion à la queue Oracle (Topic) :
package trigger;

import org.springframework.beans.factory.FactoryBean;
import oracle.jms.AQjmsSession;

import javax.jms.Topic;
import javax.jms.TopicConnectionFactory;

public class OracleAQTopicDestinationFactory implements FactoryBean {

private TopicConnectionFactory connectionFactory;
private String queueUser;
private String queueName;


public Object getObject() throws Exception {

AQjmsSession session = (AQjmsSession) connectionFactory
.createTopicConnection()
.createTopicSession(true, 0);


Topic t= session.getTopic(queueUser , queueName);
return t;
}

public Class getObjectType() {
return javax.jms.Topic.class;
}

public boolean isSingleton() {
return true;
}

public void setConnectionFactory(TopicConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}

public void setQueueUser(String queueUser) {
this.queueUser = queueUser;
}

public void setQueueName(String queueName) {
this.queueName = queueName;
}
}


Enfin la troisième, est une classe qui écoute les messages. C'est celle çi qui va recevoir un message dès qu'Oracle en publie un.

package trigger;

import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;


public class OracleNotificationListener implements MessageListener
{

public void onMessage(Message message)
{
try
{
String text = ((TextMessage) message).getText();
System.out.println("Message reçus : " + text);

} catch (Throwable t)
{
t.printStackTrace();
}
}
}

A la réception d'un message, on l'affiche bêtement dans la console.

3. Paramétrage de Spring

Il ne reste plus qu'a paramétrer dans Spring pour que tout fonctionne. Dans votre applicationContext.xml, ajouter les lignes :

<beans xmlns="http://www.springframework.org/schema/beans" xsi="http://www.w3.org/2001/XMLSchema-instance" tx="http://www.springframework.org/schema/tx" schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd ">

<bean id="oracleAQJMSListener" class="trigger.OracleNotificationListener">

</bean>

<bean id="oracleAqConnFactory" bean="oracleAqConnectionFactoryHandler" method="createConnectionFactory">

<bean id="oracleAqConnectionFactoryHandler" class="trigger.OracleAQTopicConnectionFactory">
</bean>


<bean id="cnt_queue" class="trigger.OracleAQTopicDestinationFactory">
<property name="connectionFactory" ref="oracleAqConnFactory">
<property name="queueName" value="cnt_queue">
<property name="queueUser" value="MON_USER">
</property>

<bean id="oracleAqJMSQueue" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="oracleAqConnFactory">
<property name="destination" ref="cnt_queue">
<property name="messageListener" ref="oracleAQJMSListener">
<property name="pubSubDomain" value="true">
</property>
</property></property></property></bean></property></property></bean></bean></beans>

Il ne faut pas oublier d'adapter les valeur class en respectant vos packages et nom de classes (ici les classes sont dans le package trigger).
Ici la queue s'appelle cnt_queue.
Le bean oracleAqJMSQueue est le bean d'écoute des messages (troisième classe créé).

Voila c'est tout !

Pour tester :

Lancer votre application.
Effectuez une modification sur la table où est le trigger
Un message devrait apparaitre dans la console... ça marche !!

mardi 9 juin 2009

Erreur IWAE0006E au déploiement d'une application WebSphere

Bonjour,
depuis 3 jours, sur ma machine, impossible de déploier mon application J2EE sur WebSphere en utilisant RAD !

J'avais une erreur IWAE0006E dans la console se plaignant que mon application n'était pas valide et que le web.xml manquait à l'appel ! Que nenni ! Tout était parfait pourtant dans mon projet sous RAD, j'ai trituré dans tous les sens pendant 3 jours pensant que le problème venait de ma configuration (tout marchait bien il y a encore 1 semaine!)...

J'aurai du en fait chercher du coté de mon ami Google : voici un lien qui corrigera le problème (en anglais) : http://www-01.ibm.com/support/docview.wss?uid=swg21255956

Pour résumer (je vous laisse lire l'article d'IBM), si par hasard vous avez modifié vos répertoires sources du projet (propriétés du projet/chemin de génération JAVA/Sources) et que vous avez le malheur d'avoir mis une source vers un répertoire qui n'existe plus, ça empeche le déploiement de l'application avec l'erreur enigmatique IWAE0006E dans la console...

La combine consiste à virer de la configuration du projet les répertoires sources qui n'existent plus (en modifiant le fichier settings/org.eclipse.wst.common.component de votre projet)

Voili, bon courage avec RAD et WebSphere ! (il en faut parfois!)

vendredi 5 juin 2009

Erreur : SQLGrammarException: could not get next sequence value avec Hibernate et JPA

Bonjour,
si vous utilisez Hibernate avec JPA sur une base Oracle, sur les clés, vous pouvez avoir l'exception suivante :

org.hibernate.exception.SQLGrammarException: could not get next sequence value


La raison de l'erreur est pour les clés auto incrémentées. Il faut pour que ça marche, créer une séquence.
On va mettre en place la solution sur mon exemple : une table Banque

Voici ma classe de mapping :
@Entity //entité JPA
public class Banque
{
@Id //c'est la clé primaire
@GeneratedValue() //c'est une clé générée (auto incrémentée)
@Column(name="refbqe") //nom de la colonne dans la table
private Integer id;

//les colonnes dans la table
private String Cdepos;

...

+ getter/setter
}


Connectez vous sur votre base et crééz une séquence BANQUE_SEQUENCE :

create sequence BANQUE_sequence
start with 1
increment by 1
nomaxvalue;


Cette séquence sera utilisée pour générer les clés de la table Banque. Modifier la classe Banque comme ceci :
@Entity
public class Banque
{
@Id
@SequenceGenerator(name="sequence",sequenceName="BANQUE_sequence")
@GeneratedValue(GenerationType.SEQUENCE,generator="sequence")
@Column(name="refbqe")
private Integer id;

//les colonnes dans la table
private String Cdepos;

...

+ getter/setter
}

(notez le rajout de SequenceGenerator et la modification de GeneratedValue)

Voili, c'est tout, ça devrait marcher maintenant !!

A+

mercredi 13 mai 2009

Utiliser la sécurité de WebSphere pour un projet Web dans RAD

Ce petit tuto va vous expliquer rapidement comment mettre en place un système de login robuste et performant dans un projet Web sous Web Sphere (version 6.1 ici).

On va faire cela sous RAD (Rational Application Developper).

Dans 80% des applications (et dans 99% en entreprise), on a besoin d'authentifier un utilisateur. Par authentification, on entends un système qui permet d'identifier un utilisateur de l'application, en l'occurrence ici, par son login et son mot de passe.

Gérer l'authentification est très sensible car elle peut poser des problèmes de sécurité pourtant c'est un élément élémentaire pour toute application Web. Heureusement pour nous, avec trés peu d'effort, on peut mettre en place un système trés fiable et souple en utilisant l'authentification intégrée à Web Sphere. En 10 min on pourra mettre en place ce système ! alors qu'il faudrait plusieures heures de travail si on le développerai soit même (avec tous les risques que cela comporte).

Supposons que vous avez une projet Web déjà tout prêt (projet JSP, Struts 2 etc... peu importe) dans RAD et que vous voulez y rajouter l'authentification et un système de gestion de rôle. En effet, chaque utilisateur du système n'a pas forcément les mêmes droits. Par exemple, un utilisateur lambda pourra par exemple que consulter les données alors que peut être l'administrateur pourra lui créer, supprimer ou modifier. On dit qu'on attribut des rôles aux utilisateurs. Un utilisateur peut avoir plusieurs rôles en même temps. Avec une gestion assez fine des rôles, on peut arriver à permettre ou interdire certaines fonctionnalités de l'application selon l'utilisateur.

Avant de commencer, il faut activer, si ce n'est pas déjà fait, la sécurité dans WebSphere :
  1. Ouvrir la console administrative de WebSphere
  2. Dans Sécurité/Administration, applications et infrastructure sécurisée, il faut que 'Activer la sécurité applicative' soit cochée. Si ce n'est pas le cas, éxecuter l'assistant de configuration des paramètres de sécurité.
  3. Suivre les indications de l'assistant. Notamment, on vous demandera un login et mot de passe pour se connecter à WebSphere (bien retenir ces informations car elles vous seront demandées à la prochaine connexion à la console administrative !)
  4. Sauvegarder vos modifications et redémarrer le serveur WebSphere
  5. RAD ne risque de plus fonctionner avec votre serveur. Double cliquer sur le serveur dans RAD et dans la partie sécurité : cocher "la sécurité est active sur ce serveur" puis renseigner le login et mot de passe saisis au point 3
La sécurité est désormais active sur le serveur ! Vous verrez que maintenant, les adresses sont en https et non plus en http

On va voir maintenant comment créer notre page de login. Elle va être simple : elle contient seulement un formulaire qui va envoyer les informations de connexion à Web Sphere.
Voici son code HTML :

<html>
<body>

<form action="j_security_check" method="post" />

Login : <input type="text" name="j_username" /><br>
Password : <input type="password" name="j_password" /><br>
<input type="submit" value="Connect" />
</form>

<body>
</html>


Lorsque l'utilisateur clique sur 'Connect', le login et mot de passe sont envoyées dans une servlet de WebSphere : j_security_check. Cette servlet vérifie que l'utilisateur existe bien et vérifie son mot de passe. Si l'utilisateur est connu, l'utilisateur sera authentifié sur toutes les pages de l'application Web.
Les utilisateurs sont définis directement dans WebSphere (dans la partie Sécurité ou Utilisateur et Groupe sous la console administrative). C'est assez bien fait, car on peut très bien coupler WebSphere et Active Directory de Windows, ainsi, tous les utilisateurs de Windows seront directement utilisables par notre application !!!

Maintenant il gérer la sécurité dans notre projet avec RAD :
  1. Ouvrir le projet Web dans RAD
  2. Ouvrir Web.xml (descripteur de déploiement)
  3. Aller dans l'onglet "Pages"
  4. Dans la partie "Connexion", mettre "FORM" dans la méthode d'authentification et /login.jsp dans la page de connexion. Cela indique qu'on utilise la page de login créée plus haut comme page de connexion à notre application
Il faut désormais définir les rôles de sécurité. Identifiez les et les créer :
  1. Dans Web.xml, aller dans l'onglet "Sécurité"
  2. Ajouter un roles (en haut de l'écran), par exemple le rôle Admin qui sera destiné aux administrateurs de l'application
  3. Procéder de même pour tous les roles
Une fois les rôles définis, on doit spécifier à quoi ont accès les rôles. ça peut être n'importe qu'elle ressource du site (jsp, image, feuille de style, action struts etc...) :
  1. Toujours dans l'onglet "Sécurité" de Web.xml, créer une contrainte sécurité. Une contrainte spécifie un groupe de ressource que l'on autorise pour des rôles
  2. La contrainte doit avoir au moins un pattern de ressource. Le pattern définit l'ensemble des ressources concernées : par exemple *.jsp pour toutes les jsp du site, *.action pour toutes les actions struts 2, admin*.jsp pour toutes les pages jsp commençant par admin etc...
  3. Il faut ensuite associer les roles à ces ressources. Seuls les utilisateurs ayant les rôles choisis auront accés aux ressources
Pour finir, il reste plus qu'a associer les rôles aux utilisateurs (un utilisateur peut avoir plusieurs roles). Il y a deux méthodes : à partir de la console administrative de WebSphere ou directement à partir de RAD :
  1. Dans RAD, ouvrir l'éditeur de sécurité du projet (dans l'arborescence du prjet)
  2. Les rôles créés dans Web.xml devraient apparaitre.
  3. On peut mapper des utilisateurs ou des groupes à chaque role.
  4. Créer éventuellement les utilisateurs dans WebSphere (à partir de la console administrative)
Pour tester votre application, ouvrez une page concernée par une contrainte de sécurité. Tout d'abord, l'application va vous demander un login/mdp. Choisir un utilisateur ayant le bon rôle. Vous devez avoir accés à la page. Recommencer avec un utilisateur n'ayant pas le role, l'accés à la page doit être refusé.

Note : vous devez proposer, à tout moment, à l'utilisateur de se déconnecter de l'application. Pour cela, rajouter un lien cliquable sur chacune de vos pages pointant vers l'URL : ibm_security_logout?logoutExitPage=##URL##
Remplacer ##URL## par l'adresse de la page vers laquelle aller àpres la déconnexion (par exemple la page d'acceuil de votre site)

Voili, c'est tout !

lundi 4 mai 2009

JAVA JPA : problème de persistence.xml avec RAD

Lorsqu'on essaye d'intégrer JPA (Java Persistence API) dans un projet Web sous RAD (Rational Application Developper) 6 ou 7, j'ai remarqué un petit soucis à la configuration et au démarrage de l'application sur un serveur WebSphere 6.1 (je sais pas sur les versions suivantes ou précédentes). (RAD étant basé sur Eclipse peut être que ce problème se produit aussi sous Eclipse, à vérifier)

J'ai créé un fichier de configuration persistence.xml dans le répértoire META-INF (WebContent/META-INF sous RAD) comme le préconise la documentation de JPA (un petit tour sur le site officiel http://java.sun.com/javaee/overview/faq/persistence.jsp peut ne pas faire de mal !). Dans ce fichier, j'ai juste créé une unité de persistance car il en faut au moins une pour JPA :




Ma base de données contient une table Banque donc j'ai créé la classe Java correspondante à cette table, cette classe se nomme : test.struts2.helloworld.data.Banque (package+nom de la classe) :


package test.struts2.helloworld.data;
import java.sql.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Banque
{
@Id
@GeneratedValue
private Integer refbqe;

private String nombqe;
private String vilbqe;

public String getNombqe()
{
return nombqe;
}

public void setNombqe(String nombqe)
{
this.nombqe = nombqe;
}
public String getVilbqe()
{
return vilbqe;
}
public void setVilbqe(String vilbqe)
{
this.vilbqe = vilbqe;
}

public Banque()
{
}

public Integer getRefbqe()
{
return refbqe;
}

public void setRefbqe(Integer refbqe)
{ this.refbqe = refbqe;
}
}

Au démarrage de mon application, j'avais l'exception suivante :


Caused by: java.lang.NoClassDefFoundError: WEB-INF.classes.test.struts2.helloworld.data.Banque (wrong name: test/struts2/helloworld/data/Banque)
at java.lang.ClassLoader.defineClassImpl(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:228)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:148)
at com.ibm.ws.classloader.CompoundClassLoader._defineClass(CompoundClassLoader.java:562)
at com.ibm.ws.classloader.CompoundClassLoader.findClass(CompoundClassLoader.java:514)
at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:388)
at java.lang.ClassLoader.loadClass(ClassLoader.java:573)
..etc


Tout me parait pourtant correct dans ma configuration et dans ma banque... Après m'être arraché les cheveux, je suis tombé sur un post (désolé j'ai perdu l'adresse) qui explique qu'en fait ce problème vient de RAD...

En effet, normalement JPA s'attends que persistence.xml soit, au déploiement de l'application sur le serveur Web, dans le répertoire WebContent/classes/META-INF/. JPA cherchera les classes mappant avec la base à partir du répertoire parent du répertoire de persistence.xml (c'est à dire WebContent/classes).

Mais voila, RAD au déploiement, ne créé pas le répertoire WebContent/classes/META-INF/ avec le fichier de configuration a l'intérieur, il le laisse dans WebContent/META-INF. Du coup, JPA cherche les classes mappant la base dans WebContent/ et non pas WebContent/classes d'où l'exception levée !!

Pour corriger cela, il faut un poil bidouiller :
-il faut créer un répertoire META-INF dans les sources et placer le persistence.xml dans ce répertoire
-supprimer le fichier WebContent/META-INF/persistence.xml
Au déploiement, RAD mettra bien persistence.xml dans WebContent/classes/META-INF !

Pour la 1ere partie, pour ceux qui ne savent pas faire, voici comment procéder :
-dans RAD, ouvrir son projet Web
-ouvrir la vue 'Navigateur' (menu Fenetre/Afficher la vue/Navigateur)
-créer un dossier META-INF (pas un package ni un dossier source mais un dossier tout simple) dans le dossier src/
-placer le fichier persistence.xml dans ce répertoire

Voila c'est tout simple !! Encore faut il le savoir !!