Un article sur le Débogage EJB Sans Déploiement En Utilisant l'EDI NetBeans
Cet article fait partie de la série d'articles soumis par la communauté NetBeans dans le cadre du concours "Win With NetBeans".
Introduction
Le développement d'EJB n'a jamais été facile.
Dès qu'il y a une modification dans la logique, il doit
être repackagé et redéployé dans le containeur pour
le débogage. Ici je vais vous expliquer comment les EJB
peuvent être testé avant d'être déployé.
C'est un des buts de EJB3.0.
(voir les spécifications EJB3.0 Ã
http://java.sun.com/products/ejb/docs.html).
Code source pour l'exemple discuté est également joint.
A qui s'adresse ce document
Ce document s'adresse aux développeurs EJB et tout ceux qui ont
la connaissance de Java, J2EE.
Outils Utilisés
EDI NetBeans 3.6
Processus Actuel
Le Processus
- Tous les fichiers Java sont compilés
- Tous les fichier class sont rassemblés dans un jar/ear
- Les fichiers jar sont copiés sur le serveur
- Le serveur déploie les EJB
- Le développeur débogue le code. Si le code a été modifié, les points 1 à 4 doivent être répétés.
- Certains serveurs J2EE demande le redémarrage pour le déploiement. Pour chaque déploiement, un redémarrage est alors requis.
Nouveau Processus
Le processus
- Les fichiers Java requis sont compilés
- Développeur débogue le code.Si le code a été modifié, les points 1 et 2 doivent être répété.
- Le Ccontaineur J2EE n'est pas requis pour le débogage.
Je n'ai pas à expliquer les avantages de ce style de débogage
Scénario
Supposons que nous avons à développer un Portail d'Employé en utilisant les EJB. Le design contient un EmployeeServiceEJB et DepartmentServiceEJB. EmployeeServiceEJB donne le nom de l'employé si l'id de l'employé est passé. Cet EJB retourne également le nom de département de l'employé si l'id est passé. Pour cela, il récupère d'abord l'id du département depuis EmployeeServiceEJB qui récupère le nom du département depuis DepartmentServiceEJB. Voyons comment cela peut être développé sans déployé les EJBs dans le containeur.
Classes
Séquence
Obstacles pour le débogage dans l'EDI
La classe EmployeeServiceEJB_Skel (le nom dépend du containeur) sera générée lors du déploiement dans le containeur. Elle sera générée par le containeur.
Donc, au moment du débogage, cet objet n'est pas disponible ce qui ne permet pas de déboguer l'EJB sans le déployer.
Exigences
- Un framework qui permettrait aux EJB d'être testé dans Netbeans et les mêmes objets devraient être déployés dans le containeur sans autres modifications.
- Les scripts de tests Junit devraient également tester le code dans l'EDI et le containeur sans modification de script
- Lorsque l'EDI tourne, le serveur ne doit pas être démarré, ce qui épargne de l'espace mémoire et de ce fait la performance du système.
Obstacles pour déboguer dans l'EDI
- Le containeur génère des classes qui ne sont pas disponible pour le débogage.
- Le pool de connections n'est pas disponible
surmonter le Problème généré par le Containeur en utilisant le Business Interface & ServiceLocator
Les classes générées par le containeur le sont pour la transaction, le remoting, ... Du point de vue débogage, c'est une délégation d'appel de Remote Interface vers Bean class.
Durant le débogage dans l'EDI, un work around est requis pour éviter les appels d'Objets Skeleton, comme il ne sont pas générés au moment du débogage
Business Interface
L'utilisation de méthode business interface bean peut être exécutée sans appeler de classes générées par le containeur. Mais cependant, après le déployement des beans, les méthodes devraient être appelée via les classes générées par le containeur. Cela est accompli via le Service locator.
Classes
Séquence durant le débogage
Extrait de Code. [Vérifiez la hiérarchie d'héritage dans le diagramme de classe]
EmployeeBusinessService getEmployeeBusinessService() {
EmployeeBusinessService service = new EmployeeServiceEJB();
return service;
}
Séquence après le déploiement
Extrait de Code. [ Vérifiez la hiérarchie de classe dans le diagramme de classe]
EmployeeBusinessService getEmployeeBusinessService() {
Context context = getContext("emp");
EmployeeServiceHome home = null;
Object homeObject = context.lookup("emp/ejb/EmployeeServicess");
home = (EmployeeServiceHome)PortableRemoteObject.narrow(homeObject, EmployeeServiceHome.class);
EmployeeService empService = home.create();
return empService;
}
Service Locator
- Deux différents chemins sont requis lors du développement et du déploiement.
- Dans le cas du développement, BusinessInterface est assigné avec BeanInstance.
- Si c'est déployé sur le serveur, BusinessInterface est assigné avec RemoteInstance
ServiceLocator prend cette décision sur base d'une variable d'environnement. Cette variable d'environnement est configurée sur le serveur ou EDI. Une méthode complete de service locator
public EmployeeBusinessService getEmployeeService() throws BaseException {
if( isServerDeployment() ){
try {
Context context = getContext("emp");
EmployeeServiceHome home = null;
Object homeObject = context.lookup("emp/ejb/EmployeeServices");
home =EmployeeServiceHome)PortableRemoteObject.narrow(homeObject, EmployeeServiceHome.class);
EmployeeService empService = home.create();
//INSTANCE OF EMPLOYEE BEAN REMOTE INSTANCE
return empService;
}catch(Exception e) {
e.printStackTrace();
throw new BaseException(e.getMessage());
}
}else{
//INSTANCE OF EMPLOYEE BEAN
return new EmployeeServiceBean();
}
}
protected boolean isServerDeployment() {
String DEPLOYMENT_TYPE = System.getProperty("deployment.type"); return ("Server".equalsIgnoreCase(DEPLOYMENT_TYPE))?true:false;
}
protected Context getContext(String appName) throws Exception {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
env.put(Context.SECURITY_PRINCIPAL, SECURITY_PRINCIPAL);
env.put(Context.SECURITY_CREDENTIALS, SECURITY_CREDENTIALS);
env.put(Context.PROVIDER_URL, BASE_PROVIDER_URL+appName);
System.out.println("Connecting to Base URL"+ BASE_PROVIDER_URL+appName);
return new InitialContext(env);
}
La variable d'environnement deployment.type peut être définie en utilisant l'option -d. Dans le script de démarrage du serveur -ddeployment.type=server Dans le paramètre Java de l'EDI -ddeployment.type=ide
Disponibilité Pool de Connection
Puisque le pool de connection n'est pas disponible dans l'environnement de l'EDI, une connection directe est requise au moment du débogage.
Si le code est exécuté dans la JVM du serveur, il va récupérer la connection poolée, sinon, une connection directe sera créée.
protected Connection getConnection() throws SQLException {
Connection con = null;
try {
if( isServerDeployment() ) {
con = getPooledConnection();
}else {
con = getDirectConnection();
}
}catch(SQLException sqle) {
throw sqle;
}catch (Exception e){
e.printStackTrace();
}
return con;
}
Unit Testing
Un EJB peut être testé en utilisant les scripts de test JUNIT
public void testGetEmpName() throws Exception {
EmployeeBusinessService business = EmployeeServiceLocator.getInstance().getEmployeeService();
String name= business.getEmpName("1234");
assertEquals(name,"abcd");
}
Si ce script de test est exécuté en utilisant deployment.type=ide il sera exécuté dans l'EDI, sinon, il appellera la méthode dans le containeur. Cela signifie que le même script peut être utilisé pour les tests durant le développement et après le déployement. Pour cela, les jndi.properties devraient être définis correctement.
Log4j
Si log4j est utilisé pour le logging, il devrait être initialisé avec log4j.properties. Le bout de code suivant le fait
org.apache.log4j.PropertyConfigurator.configure("{server.dir}/log4j.properties");
Copies d'écrans
Définir variables d'environnement
Débogage dans l'EDI
Débogage EJB déployé dans le containeur
Cela est réalisé en modifiant deployment.type=server
