vendredi 7 décembre 2007

Injection EJB avec JSF1.1 solution 2

Nouvelle solution plus propre (ca fera plaisir à Alexandre) et plus performante pour effectuer une injection @EJB dans un managed bean (ou back bean) JSF. L'utilisation d'un lookup local tout simplement (bien que sur Workshop ce soit pas du gâteau).

Une petite classe donc qui, avec sa simple méthode à appeller dans le contructeur de votre back bean vous permettra par réflexion d'effectuer un context lookup vers votre ejb (Champs @EJB public uniquement). Toujours en attendant l'injection @EJB dans le nouveau WorkShop.

télécharger la classe java

Pour cerain il peut se produire une erreur de lookup du style :

javax.naming.NameNotFoundException: While trying to look up comp/env/Addition/Local in /app/webapp/TEST_JSF_EBJ/12227708.; remaining name 'comp/env/Addition/Local'


Pour résoudre ce problème j'ai simplement ajouté un ServletContextListener à mon application web dans laquelle je référence mes ejb . Après le lookup local dans les back beans fonctionne a merveille...

public class testListener implements ServletContextListener {

@EJB(name = "Addition/Local")

public AdditionRemote ar;

public void contextDestroyed(ServletContextEvent arg0) { }

public void contextInitialized(ServletContextEvent arg0) { }

}




Exemple d'utilisation :


@EJB(name = "Addition/Local")

public AdditionRemote ar; // is va être injecté dans le constructeur

public testBackBean() {

fr.sihm.common.ejblocator.EJBLocator.injecterMesEJB(this);

}

public String getResultEJB() // on teste

{

if (ar == null) {

return "NOT BOUND";

} else {

return "Bouded , result = " + ar.additionner(5, 5);

}

}

mercredi 5 décembre 2007

Injection d’un EJB dans un back bean JSF 1.1

Dans sa version 10.1, BEA workshop studio propose de base de faire du JSF 1.1. Or, dans la spécification JSF 1.1, l’injection d’EJB n’est pas possible dans les back-beans.

En attendant la nouvelle version de workshop qui devrait permettre d’utiliser JSF 1.2 facilement (oui c’est déjà possible mais galère) et donc l’injection dans les back beans, je vous propose un petit « hack » maison pour permettre de ne pas trop salir vos managed beans tout en ayant un semblant d’injection (Le canada dry de l'injection EJB).

Le fonctionnement est simple, on crée un servlet listener qui possède une référence vers tous les ejb que vous utiliserez dans l’application. La norme JSF 1.1 permettant l’injection dans les servletfilters, ces références seront peuplées lors de l’exécution. Dès lors, notre tâche consistera à copier les références dans le servletcontext pour que nos back beans aient accès aux valeurs injectées.

Je vous fourni donc une classe qui par réflexion va analyser tous les champs public qui contiennent l’annotation @EJB et qui écrira (pour le listener) ou lira (pour le back bean) la valeur dans le ServletContext.

Utilisation :

Notre Listener comportra une réference vers tous les EJB utilisés (un seul dans mon exemple), et l'implémentation de la méthode contextInitialized sera toute simple :

public class testEJBInjectionListener implements ServletContextListener {

@EJB(name = "Addition/Local")

public AdditionRemote ar;

public void contextDestroyed(ServletContextEvent arg0) {

// TODO Auto-generated method stub

}

public void contextInitialized(ServletContextEvent arg0) {

tools.EJB_Initialiser.saveMyEJBs(arg0.getServletContext(),this);

}

}




Du coté du back bean, rien de plus compliqué. On fait une référence vers les EJB que l'on souhaite utiliser en conservant l'injection :

public class testBackBean {

@EJB(name = "Addition/Local")

public AdditionRemote ar;

public testBackBean()

{

tools.EJB_Initialiser.injecterMesEJB(this);

}

}


La classe utilitaire InitialiserEJB fesant le reste : télécharger la classe.

Au niveau des performances ce n'est pas terrible du tout car cela effectue un lock sur l'instance des l'EJB coté serveur (car une seule instance dans le contexte application), aucun accès concurant ne sera donc possible et il faudra attendre gentiment son tour pour accéder au bean session. A utiliser donc en attendant JSF 1.2 !

vendredi 23 novembre 2007

Tutoriel .net sur les BuildProvider

Ayant délaissé visual studio pour éclipse ces derniers mois, je souhaitait "garder la main" en .net tout en vous montrant une facette bien peu connue de .net : les BuildProviders.

Qu'est-ce qu'un build provider ?

Un build provider se présente sous la forme d'une classe héritant de System.Web.Compilation.BuildProvider et permettant de compiler pendant le développement des fichiers de la solution. Les classes ainsi créées sont accessibles via l'intellisense dans la solution.

Pour bien cerner toute la puissance de cette technologie, je vous propose d'étudier le cas d'un provider permettant de simplifier l'utilisation des sessions utilisateurs.

Trop souvent dans un projet web, les sessions deviennent rapidement un "foure-tout". De plus, c'est une bonne pratique que d'avoir un fichier recensant l'utilisation de la session dans le projet. Nous allons donc créer un build provider qui, à partir d'un fichier xml de la solution, génèreralirer et d'écrire dans la session sans ses soucier du nom des clés ou du casting.

Structure du fichier descriptif de session :


Pour commencer, créez un nouveau site asp.net. Ajoutez à la solution une nouvelle biblothèqueBuildProviderSession" .

Ajoutez ensuite une nouvelle classe nommée BPSession et héritant de System.Web.Compilation.BuildProvider

Nous allons implémenter 3 méthodes de la classe BuildProvider.
  • CompilerType : propriété qui spécifie le type de compilateur à utiliser par visual studio.
  • GenerateCode : méthode dans laquelle nous renverrons le code c# à compiler.



  • GetGeneratedType : méthode ou nous renverrons à visual studio le type généré.





Notre Build Provider est maintenant terminée, nous allons l'utiliser dans le projet web de la solution.

Pour ce faire, rien de plus simplen ajoutez au web.config (créez le si nécessaire) ces quelques lignes (sous system.web) :




La partie extension détermine pour quel types de fichier visual studio appellera notre compilateur.

Vous pouvez maintenant créer dans le répertoire app_code du site web un fichier avec l'extention dvp respectant le schéma du fichier xml précédent.

Après avoir compilé la solution (avec succès normalement), allez simplement dans le code d'une page web, défault par exemple. Et la surprise, notre classe CurrentSession est disponble :



Conclusion

Les BuildProviders sont des outils très puissants. L'exemple que j'ai choisi est simple et son intérêt est limité. Cependant, dans le cadre de développement de frameworks, cette technologie offre un outil sans égal pour simplifier la vie du développeur. Je proposerais plus tard un tutoriel sur l'écriture d'une interface graphique pour générer le fichier descriptif des sessions. Interface qui sera bien sur intégrée à Visual Studio :)

Télécharger la classe BPSession

mardi 30 octobre 2007

Utilisation des JavaAgents

En étudiant le fonctionnement de KODO en standalone, j’ai été amené à utiliser un concept qui m’était inconnu : les JavaAgents. C'est une nouveauté de Java 5 pour laquelle on trouve très peu de documentation. Je vous propose donc d'expliquer simplement son utilisation.

Définition

Un JavaAgent est une librairie « pluggable » qui tourne dans une JVM embarqué (celle du programme exécuté) et qui intercepte les chargements de classes. Cela permet donc de suivre le processus de chargement des classes d’un programme java et, si nécessaire, de modifier à chaud le comportement de la classe (mécanisme d’intercession).

Concrètement un JavaAgent se présente sous la forme d’un simple JAR contenant une classe implémentant une méthode :

public static void premain(String agentArgs, Instrumentation inst)

Le premier argument de cette méthode est un String représentant les arguments à passer à l’agent (à parser sois même avec pipe, délimiteur,…). Le deuxième est l’instance d’Instrumentalisation. C’est grâce à cette classe que l’on ajoute les transformers voulus.

ClassTransformer

Les classes implémentant l’interface ClassFileTransformer sont créées pour effectuer des modifications dans le bytecode de classes existantes. Leur implémentation est très simple puisqu’il suffit d’implémenter l’unique méthode de l’interface ClassFileTransformer.

Création d’un agent java simple

Dans cet article je vous propose de créer un agent java très simple. Il aura pour but l’affichage dans la sortir standard des classes qui sont chargée par le programme. Pour arriver à notre objectif nous aurons besoin de créer l’agent, son ClassFileTransformer, et d’extraire le tout dans un JAR correctement formaté.

Dans un nouveau projet java créez une classe myJavaAgent comme ceci :

package fr.demo.testAgent;

import java.lang.instrument.Instrumentation;
import
fr.demo.testTransformer.TestClassTransformer;

public class myJavaAgent {
public static void premain(String agentArgs, Instrumentation inst)

{
inst.addTransformer(
new TestClassTransformer());
}
}


La seule opération de l’agent est d’ajouter un classtransformer à l’instance d’instrumentalisation de la JVM du programme executé.


Code du class transformer :

package fr.demo.testAgent;
import
java.lang.instrument.ClassFileTransformer;

import java.lang.instrument.IllegalClassFormatException;

import java.security.ProtectionDomain;

public class EzClassTransformer implements ClassFileTransformer {

public byte[] transform(ClassLoader loader, String className,

Class classBeingRedefined, ProtectionDomain protectionDomain,

byte[] classfileBuffer) throws IllegalClassFormatException {

System.out.println("Je charge la classe :" + className);

return classfileBuffer;

}

}

Comme vu précédement, l’interface ClassFileTransformer se résume en une méthode à implémenter : transform. Cette méthode passe en paramètre la classe avant qu’elle soit chargée par la JVM. Elle offre la possibilité de modifier le comportement de la classe en ayant comme paramètre de retour un tableau de byte correspondant à la classe compilée. Pour l’instant nous nous contenterons simplement d’afficher que la classe est chargée en renvoyant directement la classe passée en paramètre sans modification.


Création du JAR

Un java agent se présentant sous la forme de JAR, il nous faut donc créer un JAR contenant l’agent java et le classfiletransformer (via éclipse, click droit sur projet, export, java archive). Dans le fichier META-INF/MANIFEST.MF du jar il faut ajouter l’entrée :

Premain-Class: fr.demo.testAgent.myJavaAgent

Cette entrée permet de définir à la JVM la classe du JAR jouant le rôle de l'agent (bootstrap class).

Une fois le JAR crée il ne nous reste plus qu’à le tester. Pour ce faire prenez une application java de votre choix (console, swing…) et éxécutez la simplement en ajoutant l’argument (via éclipse « open run dialog » et « arguments ») :

-javaagent:lienversjar .

Conclusion

Les AgentsJava sont très utiles pour ajouter des crochets au chargement des classes de la JVM. Certes l’utilisation que nous en avons fait dans cet article est somme toute limitée, mais les classfiletransformer offrent des possibilitée que vous n’osez même pas imaginer! Je proposerais prochainement un article montrant ce méchanisme couplé avec BCEL pour modifier a chaud les bytecode des classes : une façon de voir cette technologie d’un aspect(J?) différent (comprendra qui pourra).

vendredi 26 octobre 2007

Bean Entity StandAlone recherche CRUD générique

Petite classe java utile rédigée par mes soins qui vous permettra de ne pas perdre de temps avec vos opérations de CRUD (Create Read Update Delete ) pour les entityBeans Standalone.

Télécharger la classe

Pour l'utiliser il suffit simplement d'hériter de cette classe et d'ajouter un contructeur. Exemple avec une DAO d'un objet "Secteur" :

public class SecteurDAO extends GenericDAO {


public SecteurDAO(String entityManagerName)
{
super(entityManagerName,Secteur.class);

}
}
Bean Entity

Les beans entity doivent posséder des namedqueries pour définir comment les sélectionner. Exemple :
@Entity
@NamedQueries(value ={
@NamedQuery(query="Select a from Agence a where a.id = ?1"
,name="SelectByIdAgence") ,
@NamedQuery(query="Select a from Agence a"
,name="SelectAllAgence")})
public class Agence implements Serializable {
Il est important de garder le même nom dans les NamedQueries :SelectById et SelectAll + nom de la classe. On ajoute le suffixe de la classe car on ne peut pas avoir deux mêmes noms pour des requêtes au sein d'une même unité de persistance : Merci KODO ...

Limitations
Cette classe ne fonctionne que pour les tables ayant une clé primaire non composée (je ferai plus tard une RTB "Release to Bloggers" en ajoutant un nombre de paramètres variable pour la sélection).