JBoss Enterprise Application Platform 5 Guide d`utilisateur de JBoss

Transcription

JBoss Enterprise Application Platform 5 Guide d`utilisateur de JBoss
JBoss Enterprise Application
Platform 5
Guide d'utilisateur de JBoss
Microcontainer
à utiliser dans JBoss Enterprise Application Platform 5
Édition 5.1.0
Mark Newton
Aleš Justin
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss
Microcontainer
à utiliser dans JBoss Enterprise Application Platform 5
Édition 5.1.0
Mark Newto n
Red Hat
mark.newto n@jbo ss.o rg
Aleš Justin
Red Hat
[email protected] m
Publié par
Misty Stanley-Jo nes
Red Hat
[email protected] m
Note légale
Copyright © 2011 Red Hat, Inc.
T his document is licensed by Red Hat under the Creative Commons Attribution-ShareAlike 3.0 Unported
License. If you distribute this document, or a modified version of it, you must provide attribution to Red
Hat, Inc. and provide a link to the original. If the document is modified, all Red Hat trademarks must be
removed.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section
4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, JBoss, MetaMatrix, Fedora, the Infinity Logo,
and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux ® is the registered trademark of Linus T orvalds in the United States and other countries.
Java ® is a registered trademark of Oracle and/or its affiliates.
XFS ® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States
and/or other countries.
MySQL ® is a registered trademark of MySQL AB in the United States, the European Union and other
countries.
Node.js ® is an official trademark of Joyent. Red Hat Software Collections is not formally related to or
endorsed by the official Joyent Node.js open source or commercial project.
T he OpenStack ® Word Mark and OpenStack Logo are either registered trademarks/service marks or
trademarks/service marks of the OpenStack Foundation, in the United States and other countries and
are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or
sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
Résumé
Ce guide est destiné aux développeurs Java qui souhaitent utiliser Jboss Microcontainer pour déployer
des environnements Java modulaires et personnalisés pour leurs applications
Table des matières
Table des matières
.Préface
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . . . .
1. Conventions d'écriture
4
1.1. Conventions typographiques
4
1.2. Conventions pour citations mises en avant
5
1.3. Notes et avertissements
6
2. Obtenir de l'aide et faire des commentaires
7
2.1. Avez-vous besoin d'aide ?
7
2.2. Vos commentaires sont importants !
7
. . . . . . . I.. .Introduction
Partie
. . . . . . . . . . . . . au
. . . Microcontainer
. . . . . . . . . . . . . . . . -. .T. utoriel
. . . . . . . dirigé
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9. . . . . . . . . .
.Chapitre
. . . . . . . . .1.
. . Pré-requis
. . . . . . . . . . . .avant
. . . . . . d'utiliser
. . . . . . . . . .ce
. . .Guide
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
............
1.1. Installer Maven
10
1.2. Configuration Maven spéciale pour les exemples de Microcontainer
13
1.3. Décharger les exemples
14
.Chapitre
. . . . . . . . .2.
. . Introduction
. . . . . . . . . . . . . .sur
. . . la
. . .Microcontainer
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
............
2.1. Caractéristiques
16
2.2. Définitions
16
2.3. Installation
17
.Chapitre
. . . . . . . . .3.
. . Services
. . . . . . . . . .de
. . .construction
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
............
3.1. Introduction à l'exemple Ressources Humaines
18
3.2. Compiler l'exemple de projet HRManager
19
3.3. Créer des POJO
19
3.3.1. Descripteurs de déploiement XML
19
3.4. Connecter les POJO ensemble.
19
3.4.1. Considérations spéciales
20
3.5. T ravailler avec des services
20
3.5.1. Configuration d'un service
21
3.5.2. T ester un service
21
3.5.3. Packager un service
23
.Chapitre
. . . . . . . . .4. . .Utiliser
. . . . . . . les
. . . .services
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
............
4.1. Amorçage de Microcontainer
28
4.2. Déployer le service
29
4.3. Accès direct
30
4.4. Accès indirect
32
4.5. Le chargement de classes dynamique
33
4.5.1. Problems With Classloaders Created with Deployment Descriptors
38
.Chapitre
. . . . . . . . .5.
. . Ajout
. . . . . . de
. . . .comportement
. . . . . . . . . . . . . . .AOP
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .39
...........
5.1. Créer un aspect
39
5.2. Configurer le Microcontainer pour AOP
41
5.3. Appliquer un Aspect
43
5.4. Lifecycle Callbacks
45
5.5. Ajout de Recherche de service (Look-ups) par JNDI
47
. . . . . . . II.
Partie
. . .Concepts
. . . . . . . . . .avancés
. . . . . . . . . de
. . . Microcontainer
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4. .9. . . . . . . . . .
.Chapitre
. . . . . . . . .6.
. . Modèles
. . . . . . . . . .de
. . .composants
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
............
6.1. Interactions permises avec les modèles de composants
50
6.2. Un bean sans dépendances
50
6.3. Utilisation de Microcontainer avec Spring
50
1
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
6.3. Utilisation de Microcontainer avec Spring
6.4. Utilisation de Guice avec le Microcontainer
6.5. Mbeans hérités, et comment mixer différents modèles de composants
6.6. Exposer les POJO en tant que MBeans
50
51
53
54
.Chapitre
. . . . . . . . .7.
. . Injection
. . . . . . . . . .de
. . .dépendances
. . . . . . . . . . . . . . avancées
. . . . . . . . . . .et
. . .IoC
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
............
7.1. Usine de valeurs
57
7.2. Callbacks
59
7.3. Mode d'accès de bean
61
7.4. Bean Alias
62
7.5. Support d'annotations XML (ou Métadonnées)
62
7.6. Autowire
65
7.7. Usine de bean
65
7.8. Constructeur de métadonnées de beans
68
7.9. Personnalisation du chargeur de classes.
69
7.10. Mode Controller
70
7.11. Cycle
71
7.12. Offre et demande
72
7.13. Installs
72
7.14. Lazy Mock
73
7.15. Cycle de vie
74
.Chapitre
. . . . . . . . .8.
..T
. .he
. . .Virtual
. . . . . . . File
. . . . .System
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
............
8.1. VFS Public API
78
8.2. VFS Architecture
87
8.3. Existing Implementations
87
8.4. Extension Hooks
88
8.5. Features
88
.Chapitre
. . . . . . . . .9.
. . La
. . . .couche
. . . . . . . .de
. . .chargement
. . . . . . . . . . . . .de
. . .classe
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
............
9.1. Chargeur de classes
90
9.2. Chargement de classes
97
9.3. ClassLoading VFS
102
.Chapitre
. . . . . . . . .10.
. . . .T. he
. . . Virtual
. . . . . . . .Deployment
. . . . . . . . . . . . Framework
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104
.............
10.1. Agnostic Handling of Deployment T ypes
104
10.2. Separation of Structure Recognition From Deployment lifecycle logic
104
10.3. Natural Flow Control in the form of Attachments
107
10.4. Client, User, and Server Usage and Implementation Details
108
10.5. Single State Machine
108
10.6. Scanning Classes for Annotations
109
. . . . . . . . . . . .de
Historique
. . .révision
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
.............
2
Table des matières
3
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Préface
1. Conventions d'écriture
Ce manuel utilise plusieurs conventions pour souligner l'importance de certains mots ou expressions,
mais aussi en vue d'attirer l'attention sur certains passages d'informations précis.
Pour les éditions sur support papier et numérique (PDF), ce manuel utilise des caractères issus de
Liberation Fonts. La police de caractères Liberation Fonts est également utilisée pour les éditions HT ML
si elle est installée sur votre système. Sinon, des polices de caractères alternatives équivalentes sont
utilisées. Notez que Red Hat Enterprise Linux 5 et versions supérieures contiennent la police Liberation
Fonts par défaut.
1.1. Conventions typographiques
Quatre conventions typographiques sont utilisées pour attirer l'attention sur certains mots et
expressions. Ces conventions et les circonstances auxquelles elles s'appliquent sont les suivantes.
Caractères gras à espacem ent fixe
Utilisé pour surligner certaines entrées du système, y compris les commandes shell, les noms de
fichiers et les chemins d'accès. Également utilisé pour surligner les touches et les combinaisons de
touches. Par exemple :
Pour consulter le contenu du fichier m on_nouvel_ouvrage_littéraire qui se situe
dans votre dossier courant, saisissez la commande cat
m on_nouvel_ouvrage_littéraire à la demande du terminal et appuyez sur Entrée
pour exécuter la commande.
L'exemple ci-dessus contient un nom de fichier, une commande shell et une touche, tous présentés
sous forme de caractères gras à espacement fixe et tous bien distincts grâce au contexte.
Les combinaisons de touches se distinguent des touches individuelles par le signe « plus », qui
connecte les différentes parties de la combinaison. Par exemple :
Appuyez sur Entrée pour exécuter la commande.
Appuyez sur Ctrl+Alt+F2 pour basculer sur un terminal virtuel.
Le premier exemple présente une touche particulière sur laquelle appuyer. Le second exemple affiche
une combinaison de touches : un ensemble de trois touches sur lesquelles il faut appuyer
simultanément.
Si le code source est mentionné, les noms de classes, les méthodes, les fonctions, les noms de
variables et les valeurs de retour citées dans un paragraphe seront présentées comme ci-dessus, en
caractères gras à espacem ent fixe. Par exemple :
Les classes de fichiers comprennent le nom de classe filesystem pour les noms de
fichier, file pour les fichiers et dir pour les dossiers. Chaque classe correspond à un
ensemble de permissions associées.
Caractères gras proportionnels
Cette convention marque le surlignage des mots ou phrases que l'on rencontre sur un système,
comprenant des noms d'application, des boîtes de dialogue textuelles, des boutons étiquettés, des
4
Préface
cases à cocher et des boutons d'options mais aussi des intitulés de menus et de sous-menus. Par
exemple :
Sélectionnez Système → Préférences → Souris à partir de la barre du menu principal
pour lancer les Préférences de la souris. À partir de l'onglet Boutons, cliquez sur la
case à cocher Pour gaucher puis cliquez sur Ferm er pour faire passer le bouton
principal de la souris de la gauche vers la droite (ce qui permet l'utilisation de la souris par
la main gauche).
Pour insérer un caractère spécial dans un fichier gedit, choisissez Applications →
Accessoires → T able des caractères depuis la barre du menu principal. Ensuite,
choisissez Recherche → T rouver… depuis la barre du menu T able des caractères,
saisissez le nom du caractère dans le champ Recherche puis cliquez sur Suivant. Le
caractère recherché sera surligné dans la T able des caractères. Double-cliquez sur
le caractère surligné pour le placer dans le champ T exte à copier, puis cliquez sur le
bouton Copier. Vous pouvez désormais revenir à votre document et choisir Modifier →
Coller depuis la barre du menu gedit.
Le texte ci-dessus contient des noms d'applications, des noms de menus et d'autres éléments
s'appliquant à l'ensemble du système, des boutons et textes que l'on trouve dans une interface
graphique. Ils sont tous présentés sous la forme gras proportionnel et identifiables en fonction du
contexte.
Italique gras à espacement fixe ou Italique gras proportionnel
Qu'ils soient en caractères gras à espacement fixe ou à caractères gras proportionnels, l'ajout de
l'italique indique la présence de texte remplaçable ou variable. Les caractères en italique indiquent la
présence de texte que vous ne saisissez pas littéralement ou de texte affiché qui change en fonction
des circonstances. Par exemple :
Pour se connecter à une machine distante en utilisant ssh, saisissez ssh nom
d'utilisateur@ domain.name (nom.domaine) après l'invite de commande de la console.
Si la machine distante est exem ple.com et que votre nom d'utilisateur pour cette machine
est john, saisissez ssh john@ exam ple.com .
La commande m ount -o rem ount système de fichiers monte le système de fichiers
nommé. Ainsi, pour monter /hom e dans le système de fichiers, la commande est m ount -o
rem ount /hom e.
Pour connaître la version d'un paquet actuellement installé, utilisez la commande rpm -q
paquet. Elle vous permettra de retourner le résultat suivant : version-de-paquet.
Remarquez que les mots en gras italique ci-dessus — username (nom d'utilisateur), domain.name
(nom.domaine), file-system (système de fichiers), package (paquetage), version et release (sortie
commerciale). Chaque mot est un espace réservé au texte, soit pour le texte que vous entrez lors de la
saisie d'une commande, soit pour le texte affiché par le système.
Mis à part l'utilisation habituelle de présentation du titre d'un ouvrage, les caractères italiques indiquent
l'utilisation initiale d'un terme nouveau et important. Ainsi :
Publican est un système de publication DocBook.
1.2. Conventions pour citations mises en avant
Les sorties de terminaux et les citations de code source sont mis en avant par rapport au texte
avoisinant.
5
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
avoisinant.
Les sorties envoyées vers un terminal sont en caractères Rom ains à espacem ent fixe et
présentées ainsi :
books
books_tests
Desktop
Desktop1
documentation
downloads
drafts
images
mss
notes
photos
scripts
stuff
svgs
svn
Les citations de code source sont également présentées en rom ains à espacem ent fixe mais
sont présentés et surlignés comme suit :
package org.jboss.book.jca.ex1;
import javax.naming.InitialContext;
public class ExClient
{
public static void main(String args[])
throws Exception
{
InitialContext iniCtx = new InitialContext();
Object
ref
= iniCtx.lookup("EchoBean");
EchoHome
home
= (EchoHome) ref;
Echo
echo
= home.create();
System.out.println("Created Echo");
System.out.println("Echo.echo('Hello') = " + echo.echo("Hello"));
}
}
1.3. Notes et avertissements
Enfin, nous utilisons trois styles visuels pour attirer l'attention sur des informations qui auraient pu être
normalement négligées :
Note
Une remarque est une forme de conseil, un raccourci ou une approche alternative par rapport à
une tâche à entreprendre. L'ignorer ne devrait pas provoquer de conséquences négatives, mais
vous pourriez passer à côté d'une astuce qui vous aurait simplifiée la vie.
Important
Les blocs d'informations importantes détaillent des éléments qui pourraient être facilement
négligés : des modifications de configurations qui s'appliquent uniquement à la session actuelle
ou des services qui ont besoin d'être redémarrés avant toute mise à jour. Si vous ignorez une
case étiquetée « Important », vous ne perdrez aucunes données mais cela pourrait être source
de frustration et d'irritation.
6
Préface
Avertissement
Un avertissement ne devrait pas être ignoré. Ignorer des avertissements risque fortement
d'entrainer des pertes de données.
2. Obtenir de l'aide et faire des commentaires
2.1. Avez-vous besoin d'aide ?
Si vous rencontrez des difficultés avec l'une des procédures décrites dans cette documentation, veuillez
visiter le Portail Client Red Hat sur http://access.redhat.com. Sur le portail client, vous pourrez :
effectuer des recherches ou naviguer sur la base de connaissances d'articles de support
techniques concernant les produits Red Hat.
soumettre une requête de support au service Red Hat Global Support Services (GSS).
accéder aux documents des autres produits de Red Hat.
Red Hat est l'hôte de nombreuses listes de diffusion traitant de ses logiciels et technologies. Vous
trouverez un ensemble des listes de diffusion disponibles au public sur
https://www.redhat.com/mailman/listinfo. Cliquez sur le nom d'une liste pour vous inscrire à celle-ci ou
pour accéder à ses archives.
2.2. Vos commentaires sont importants !
Si vous repérez une erreur de typographie dans ce guide, ou si vous pensez à un moyen de parfaire ce
guide, faîtes-nous en part ! Soumettez-nous un rapport dans Bugzilla sous le produit JBoss
Enterprise Application Platform 5 et sous le composant docJBoss_Microcontainer_User_Guide. Le lien suivant vous conduira vers un format de rapport tout
préparé pour le produit dont il s'agit : http://bugzilla.redhat.com/.
Remplissez le formulaire suivant dans Bugzilla sous le champ Description. Veillez à être aussi
précis que possible quand vous décrivez le problème; cela nous permettra de régler le problème plus
rapidement.
URL du Document :
Numéro et Nom de Section :
Description du problème :
Suggestions pour améliorer :
Informations supplémentaires :
N'oubliez pas de mentionner votre nom de façon à ce que nous puissions vous donner tout le crédit que
vous méritez à soulever le problème en question.
7
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
8
Partie I. Introduction au Microcontainer - Tutoriel dirigé
Partie I. Introduction au Microcontainer - Tutoriel dirigé
9
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Chapitre 1. Pré-requis avant d'utiliser ce Guide
Pour utiliser les exemples de ce guide, vous aurez besoin d'installer et de configurer des logiciels de
support, et décharger le code pour les exemples.
1.1. Installer Maven
Les exemples utilisés dans ce projet nécessitent Maven v2.2.0 ou version supérieure. Décharger
Maven directement de la page d'accueil d'Apache Maven, puis installer et configurer votre système
comme expliqué dansProcédure 1.1, « Installer Maven ».
Procédure 1.1. Installer Maven
1. Vérifiez que Java Developer Kit 1.6 ou version supérieure est installé. Il s'agit
également d'un pré-requis pour Enterprise Platform.
Vérifiez que Java est installé dans votre système et que vous avez installé la variable
d'environnement JAVA_HOME dans votre ~/.bash_profile pour Linux, ou dans Propriété
Système de Windows. Pour obtenir davantage d'informations sur les variables d'environnement,
voir l'étape Étape 4 de cette procédure.
2. Décharger Maven
Note
Cette étape et les étapes suivantes assument que vous avez sauvegardé Maven dans la
location recommandée pour votre système d'exploitation. Maven, à la manière de toute
autre application Java, peut être installé dans n'importe quelle location raisonnable de votre
système.
Visit http://maven.apache.org/download.html.
Cliquer sur le lien d'archives compressées et compilées apache-m aven-2.2.1-bin.zip
Sélectionner un miroir de déchargement à partir de la liste.
Pour les utilisateurs Linux
Sauvegarder l'archive compressée dans votre répertoire hom e.
Pour les utilisateurs Windows
Sauvegarder l'archive compressée dans votre répertoire C:\Docum ents and
Settings\user_name.
3. Installer Maven
Pour les utilisateurs Linux
Extraire le fichier compressé dans votre répertoire hom e. Si vous sélectionnez l'archive
compressée à l'étape 2, et que vous ne renommez pas le répertoire, le répertoire extrait est
nommé apache-m aven-version.
Pour les utilisateurs Windows
Extraire l'archive compressée de C:\Program Files\Apache Software Foundation. Si vous avez
sélectionné l'archive compressée à l'étape 2, et que vous ne renommez pas le répertoire, le
10
Chapitre 1. Pré-requis avant d'utiliser ce Guide
répertoire extrait sera nommé apache-m aven-version.
4. Configurer les variables d'environnement
Pour les utilisateurs Linux
Ajouter les lignes suivantes à votre profil ~/.bash_profile. Changer le nom d'utilisateur
[username] pour qu'il corresponde à votre nom d'utilisateur, et pour que le répertoire Maven
corresponde bien au nom du répertoire. Le numéro de version peut être différent du numéro listé
ci-dessous.
export M2_HOME=/home/[username]/apache-maven-2.2.1 export M2=$M2_HOME/bin
export
PATH=$M2:$PATH
En insérant M2 au début de votre chemin d'accès, la version Maven que vous venez d'installer
correspondra à la version à utiliser par défaut. Vous voudrez sans doute également définir le
chemin d'accès de votre variable d'environnement JAVA_HOME dans la location du JDK de votre
système.
Pour les utilisateurs Windows
Ajouter les variables d'environnement M2_HOME, M2, et JAVA_HOME.
a. Appuyer sur Start+Pause|Break. La boîte de dialogue des Propriétés Système est
affichée.
b. Cliquer sur l'onglet Advanced, puis sur le bouton Environm ent Variables.
c. Sous System Variables, sélectionner Path.
d. Cliquer sur Edit, et ajouter à la fin les deux chemins d'accès Maven un point virgule pour
séparer chaque entrée. Les point d'interrogation ne sont pas requis autour des chemins.
Ajouter la variable M2_HOME et définir le chemin à C:\Program Files\Apache
Software Foundation\apache-m aven-2.2.1.
Ajouter la variable M2 et définir la valeur à %M2_HOME%\bin.
e. Dans la même boîte de dialogue, créer la variable d'environnement JAVA_HOME :
Ajouter la variable %JAVA_HOME% et définir la valeur de la location pour votre JDK. Par
exemple, C:\Program Files\Java\jdk1.6.0_02.
f. Dans le même dialogue, mettez à jour ou créez la variable d'environnement de chemin
d'accès :
Ajouter la variable %M2% pour permettre à Maven d'être exécuté à partir de la ligne de
commande.
Ajouter la varaible %JAVA_HOME%\bin pour définir le chemin d'accès vers l'installation
Java qui convient.
g. Cliquer sur OK jusqu'à ce que la boîte de dialogues System Properties se ferme.
5. Modifier .bash_profile
Pour les utilisateurs Linux uniquement
Pour mettre à jour les changements apportés à .bash_profile dans la session courante, sourcer
votre .bash_profile.
[localhost]$ source ~/.bash_profile
11
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
6. Mettre à jour votre profil de terminal gnome
Pour les utilisateurs Linux uniquement
Mettez à jour le profil de terminal pour veiller à ce que les itérations suivantes du terminal gnome
(ou terminal Konsole) puisse lire les mêmes variables.
a. Cliquer sur Edit → Profiles
b. Sélectionner Default, et cliquer sur le bouton Edit.
c. Dans la boîte de dialogue Editing Profile, cliquer sur l'onglet T itle and Com m and.
d. Sélectionner la case Run com m and as login shell.
e. Fermer toutes les boîtes de dialogue ouvertes du T erminal.
7. Vérifier les changements de variables d'environnement et l'installation Maven
Pour les utilisateurs Linux
Pour s'assurer que les changements ont été implémentés correctement, ouvrir un terminal et
exécuter les commandes suivantes :
Exécuter echo $M2_HOME, qui devrait retourner le résultat suivant.
[localhost]$ echo $M2_HOME /home/username/apache-maven-2.2.1
Exécuter echo $M2, qui devrait retourner le résultat suivant.
[localhost]$ echo $M2 /home/username/apache-maven-2.2.1/bin
Exécuter echo $PAT H, et vérifier que le répertoire Maven /bin soit inclus.
[localhost]$ echo $PATH /home/username/apache-maven-2.2.1/bin
Exécutez which m vn, qui doit afficher le chemin d'accès à l'exécutable au fichierMaven
executable.
[localhost]$ which mvn ~/apache-maven-2.2.1/bin/mvn
Exécuter m vn -version, qui doit afficher la version Maven, la version Java associée, et les
informations de système d'exploitation.
[localhost]$ $ mvn -version Apache Maven 2.2.1 (r801777; 2009-08-07
05:16:01+1000) Java version:
1.6.0_0 Java home: /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre
Default locale: en_US, platform encoding: UTF-8 OS
name: "Linux" version: "2.6.30.9-96.fc11.i586" arch: "i386" Family:
"unix"
Pour les utilisateurs Windows
Pour vérifier que les changements ont été implémentés correctement, ouvrir un terminal et
exécuter la commande suivante :
Dans une invite de commande, exécuter m vn -version
12
Chapitre 1. Pré-requis avant d'utiliser ce Guide
C:\> mvn -version Apache
Maven 2.2.1 (r801777; 2009-08-06 12:16:01-0700) Java version:
1.6.0_17 Java home: C:\Sun\SDK\jdk\jre Default
locale: en_US, platform encoding: Cp1252 OS name: "windows xp"
version: "5.1" arch:
"x86" Family: "windows"
Vous avez maintenant configuré Maven avec succès pour utilisation avec les exemples de ce guide.
1.2. Configuration Maven spéciale pour les exemples de
Microcontainer
Maven est un système de génération modulaire qui extrait les dépendances selon les besoins. Les
exemples de ce guide assument que vous avez inclus le bloc d'XML dans Exemple 1.1, « Exemple de
fichier settings.xm l » dans votre ~/.m 2/settings.xm l (Linux) ou C:\Docum ents and
Settings\username\.m 2\settings.xm l (Windows). Si le fichier n'existe pas déjà, vous pouvez
commencer par le créer.
13
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 1.1. Exemple de fichier settings.xm l
<settings>
<profiles>
<profile>
<id>jboss.repository</id>
<activation>
<property>
<name>!jboss.repository.off</name>
</property>
</activation>
<repositories>
<repository>
<id>snapshots.jboss.org</id>
<url>http://snapshots.jboss.org/maven2</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>repository.jboss.org</id>
<url>http://repository.jboss.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repository.jboss.org</id>
<url>http://repository.jboss.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>snapshots.jboss.org</id>
<url>http://snapshots.jboss.org/maven2</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
</settings>
1.3. Décharger les exemples
Les exemples de ce guide vous montrent comment créer un projet Maven qui dépend de JBoss
Microcontainer, en utilisant Maven. Vous pouvez les décharger à partir de images/examples.zip . Cette
location peut changer, mais est incluse pour l'occasion.
Une fois que vous aurez déchargé le fichier Z IP qui contient les exemples, l'extraire dans une location
pratique et regardez les exemples pour vous familiariser avec leur structure.
14
Chapitre 1. Pré-requis avant d'utiliser ce Guide
15
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Chapitre 2. Introduction sur la Microcontainer
Le Microcontainer de JBoss est une refactorisation du micronoyau JMX JBoss pour supporter le
déploiement POJO direct et autonome en dehors du serveur d'applications de JBoss.
\t\nLe Microcontainer est conçu pour répondre aux besoins spécifiques des développeurs Java qui
souhaitent utiliser des techniques de programmation orientées objet pour déployer rapidement des
logiciels. En outre, il permet aux logiciels d'être déployés sur une vaste gamme de matériel, de platesformes informatiques mobiles, aux environnements de calcul en réseau à grande échelle et tout le reste.
2.1. Caractéristiques
T outes les caractéristiques du micronoyau JMX
Déploiement POJO direct (nul besoin de Standard/XMBean ou MBeanProxy)
Injection de dépendance de style IOC directe
Amélioration de la gestion du cycle de vie
Contrôle supplémentaire des dépendances
Intégration AOP transparente
Système de fichiers virtuel
Framework de déploiement virtuel
Chargement de classes OSGi
2.2. Définitions
Ce guide utilise certains termes qui ne sont sans doute pas familiers. Certains sont définis dans Liste
de définitions du Microcontainer.
Liste de définitions du Microcontainer
Micronoyau JMX
Le micronoyau JMX JBoss est un environnement modulaire de Java. La différence avec un
environnement régulier comme J2EE, c'est que le développeur est en mesure de choisir
exactement quels composants doivent faire partie de son environnement et quels composants
abandonner.
POJO
Un Plain Old Java Object (POJO) est un objet modulaire, réutilisable Java. Le nom est utilisé
pour souligner qu'un objet donné est un Objet Java ordinaire, et non pas un objet spécial, et
plus particulièrement, pas un JavaBean Enterprise. Le terme fut inventé par Martin Fowler,
Rebecca Parsons et Josh MacKenzie en Septembre 2000 à l'occasion d'une discussion au
cours de laquelle ils soulignèrent les avantages d'encoder la logique commerciale dans des
objets java réguliers plutôt due dans des beans d'entité.
Java Bean
Un Java Bean est un composant de logiciel réutilisable qui peut être manipulé visuellement par
un outil de constructeur.
Un Java Bean est un morceau de code indépendant. Il ne doit pas hériter d'une interface ou
classe de base particulière. Malgré que les Java Beans sont principalement créés en IDE
graphiques, ils peuvent également être développés dans de simples éditeurs de texte.
16
Chapitre 2. Introduction sur la Microcontainer
AOP
Aspect-Oriented Programming (AOP) est un paradigme de programmation, dans lequel des
fonctions secondaires ou de support sont isolées de la logique commerciale du programme
principal. Il s'agit d'un sous-ensemble de la programmation orientée-objet.
2.3. Installation
Le Microcontainer fait partie intégrale de la plateforme Enterprise. Vous trouverez davantage
d'informations sur la façon d'installer et de configurer Enterprise Platform dans le Guide d'administration
et de configuration.
17
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Chapitre 3. Services de construction
Les services sont des morceaux de code qui réalisent des tâches utiles à plusieurs clients. Dans le but
qui nous intéresse, nous allons ajouter plusieurs contraintes à la définition d'un service. Les services
doivent posséder des noms uniques qui pourront être référencés ou appelés par les clients. Les
aspects internes d'un service doivent être invisibles et ne doivent pas être d'aucune importance au
client. Il s'agit du concept de la "black box" OOP (Object-oriented programming). Dans OOP, chaque
objet est indépendant, et aucun autre objet n'a besoin de savoir comment il effectue son travail.
Dans le contexte précis d'un Microcontainer, les services sont construits à partir des POJO. Un POJO
est pratiquement un service en lui-même, mais on ne peut y accéder par un nom unique, et il doit être
créé par le client qui en a besoin.
Malgré qu'un POJO doit être créé en cours d'exécution par un client, il n'a pas besoin d'être implémenté
par une classe séparée pour pouvoir fournir une interface bien définie. Dans la mesure ou les champs
et les méthodes ne sont pas retirées, et que l'accès n'est pas limité, vous n'aurez pas besoin de
recompiler les clients pour qu'ils utilisent une nouveau POJO.
Note
L'implémentation d'une interface est uniquement nécessaire pour permettre au client de choisir
entre des implémentations différentes. Si le client est compilé avec une interface, on peut fournir
plusieurs implémentations de l'interface sans avoir à recompiler le client. L'interface veille à ce
que les signatures de méthodes ne changent pas.
Le reste de ce guide consiste à créer un service de Ressources Humaines, avec le Microcontainer pour
capturer et modulariser la logique commerciale de l'application. Une fois que le Microcontainer est
installé, l'exemple de code se situe dans le fichier suivant
exam ples/User_Guide/gettingStarted/hum anResourcesService.
3.1. Introduction à l'exemple Ressources Humaines
Au fur et à mesure que vous vous familiarisez avec la structure de répertoire de fichiers de l'exemple,
notez qu'il utiliser le Maven Standard Directory Layout.
Les fichiers source de Java se situent dans les packages qui se toruvent dans le répertoire
exam ples/User_Guide/gettingStarted/hum anResourcesService/src/m ain/java/org/j
boss/exam ple/service, après que vous ayez extrait le fichier Z IP. Chacune de ces classes
représente un simple POJO qui n'implémente aucune interface spéciale. La classe la plus importante est
HRManager, qui représente le point d'entrée du service qui fournit toutes les méthodes publiques que
les clients vont appeler.
Méthodes fournies par la classe HRManager
addEm ployee(Employee employee)
rem oveEm ployee(Employee employee)
getEm ployee(String firstName, String lastName)
getEm ployees()
getSalary(Employee employee)
setSalary(Employee employee, Integer newSalary)
isHiringFreeze()
18
Chapitre 3. Services de construction
setHiringFreeze(boolean hiringFreeze)
getSalaryStrategy()
setSalaryStrategy(SalaryStrategy strategy)
\t\nLe Service des ressources humaines est composé d'une poignée de classes qui maintiennent une
liste des employés et leurs coordonnées (adresses et salaires, dans ce cas). Par l'interface
SalaryStrategy , il est possible de configurer le HRManager de sorte que des implémentations de
stratégie de salaire différents soient disponibles pour placer des limites minimales et maximales sur les
salaires pour les rôles différents d'employés.
3.2. Compiler l'exemple de projet HRManager
Afin de compiler le code source, lancez m vn com pile à partir du répertoire
hum anResourcesService/. Cela va créer un nouveau répertoire intitulé target/classesqui
contient les classes compilées. Pour nettoyer le projet et retirer le répertoire cible, lancez la commande
m vn clean.
3.3. Créer des POJO
Avant qu'un POJO puisse être utilisé, vous devrez le créer. Vous aurez besoin d'un mécanisme de
nommage qui vous permette d'enregistrer une référence à l'instance du POJO par un nom. Les clients
ont besoin d'utiliser le POJO.
Le Microcontainer fournit un tel mécanisme : un Controller. Le contrôleur vous permet de déployer vos
services basés-POJO dans un environnement en cours d'exécution.
3.3.1. Descripteurs de déploiement XML
Après la compilation des classes, utilisez un descripteur de déploiement de XML pour en créer des
instances. Le descripteur contient une liste de beans représentant des instances individuelles. Chaque
bean a un nom unique, afin qu'il puisse être appelée par le client au moment de l'exécution. Le
descripteur suivant déploie une instance du HRManager :
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
<bean name="HRService" class="org.jboss.example.service.HRManager"/>
</deployment>
Cet XML crée une instance de la classe HRManager et l'enregistre avec le nom HRService. Ce fichier
est alors passé à un déployeur XML associé à un Microcontainer en cours d'exécution, qui procède au
même déploiement, et instancie les beans.
3.4. Connecter les POJO ensemble.
Les instances POJO individuelles ne fournissent que de relativement simples comportements. La
puissance réelle des POJO provient du fait qu'on peut les connecter ensemble pour entreprendre des
taches complexes. Comment connecter des POJO ensemble pour choisir des implémentations de
stratégie de salaires différentes ?
C'est ce que le descripteur de déploiement XML fait :
19
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
<bean name="HRService" class="org.jboss.example.service.HRManager">
<property name="salaryStrategy"><inject bean="AgeBasedSalary"/></property>
</bean>
<bean name="AgeBasedSalary"
class="org.jboss.example.service.util.AgeBasedSalaryStrategy"/>
</deployment>
Cet XML crée une instance de l'application de la stratégie choisie salaire en incluant un élément <bean>
supplémentaire. Cette fois, AgeBasedSalaryStrategy est choisi. Ensuite le code injecte une référence à
ce bean dans l'instance de HRManager créé à l'aide du bean HRService. L'injection est possible parce
que la classe HRManager contient une méthode setSalaryStrategy(SalaryStrategy
strategy). Dans les coulisses, JBoss Microcontainer appelle cette méthode sur l'instance de
HRManager nouvellement créée et passe une référence à l'instance AgeBasedSalaryStrategy.
Le descripteur de déploiement XML entraîne la même séquence d'événements comme si vous aviez
écrit le code suivant :
HRManager hrService = new HRManager();
AgeBasedSalaryStrategy ageBasedSalary = new AgeBasedSalaryStrategy();
hrService.setSalaryStrategy(ageBasedSalary);
En plus de faire des injections par les méthodes de setter de propriété, JBoss Microcontainer peut
également faire des injections par des paramètres de constructeur si nécessaire. Pour plus de détails
sur la question, consulter le chapitre 'Injection' dans la partie II 'Développement de POJO'.
3.4.1. Considérations spéciales
Malgré qu'il soit possible de créer des instances de classes par l'élément <bean> du descripteur de
déploiement, ce n'est pas toujours le meilleur moyen. Ainsi, créer des instances des classes Em ployee
et Address n'est pas nécessaire, parce que le client les crée en réponse à une saisie de la part de
l'utilisateur. Ils font partie du service mais ne sont pas répertoriés dans le descripteur de déploiement.
Commenter votre code.
Vous pouvez définir des beans multiples au sein d'un descripteur de déploiement tant qu'ils ont chacun
a un nom unique, qui est utilisé pour effectuer l'injection comme indiqué ci-dessus. Cependant tous les
beans ne représentent pas nécessairement tous des services. Alors qu'un service peut être implémenté
à l'aide d'un seul bean, les beans sont généralement utilisés en combinaison. Un bean représente
typiquement le point d'entrée du service et contient les méthodes publiques appelées par les clients.
Dans cet exemple, le point d'entrée est le bean HRService. Le descripteur de déploiement XML n'indique
pas si un bean représente un service ou s'il est le point d'entrée de service. C'est une bonne idée
d'utiliser des commentaires et un schéma de nommage évident pour délimiter les beans de service des
beans de non-service.
3.5. Travailler avec des services
Après avoir créé des POJO et les avoir connecté ensemble pour former des services, vous aurez
besoin de configurer les services, de les tester et de les mettre en packages.
20
Chapitre 3. Services de construction
3.5.1. Configuration d'un service
Les services peuvent être configurés de deux façon différentes au moins :
Injecter des références entre les instances de POJO
Injecter des valeurs dans les propriétés de POJO
Dans cet exemple, la seconde méthode est utilisée. Le descripteur de déploiement suivant configure
l'instance du HRManager des façons suivantes :
Un gel d'embauche est implémenté.
AgeBasedSalaryStrategy implémente les nouvelles valeurs de salaire minimum et maximum.
L'injection des références entre les instances de POJO est une façon de configurer un service.
Cependant, nous pouvons également injecter des valeurs dans les propriétés POJO. Le descripteur de
déploiement suivant nous montre comment configurer l'instance HRManager pour avoir un gel
d'embauche et pour que le AgeBasedSalaryStrategy ait des valeurs de salaire minimum et maximum :
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
<bean name="HRService" class="org.jboss.example.service.HRManager">
<property name="hiringFreeze">false</property>
<property name="salaryStrategy"><inject bean="AgeBasedSalary"/></property>
</bean>
<bean name="AgeBasedSalary"
class="org.jboss.example.service.util.AgeBasedSalaryStrategy">
<property name="minSalary">1000</property> <property
name="maxSalary">80000</property>
</bean>
</deployment>
Les classes doivent avoir des méthodes de setter publiques pour les propriétés qui conviennent, de
façon à pouvoir injecter les valeurs. Par exemple, la classe HRManager possède une méthode
setHiringFreeze(boolean hiringFreeze) et la classe AgeBasedSalaryStrategy possède
les méthodes setMinSalary(int m inSalary) et setMaxSalary(int m axSalary).
Les valeurs du descripteur de déploiement sont converties à partir de strings dans les types qui
conviennent (booléen, int etc...) par les PropertyEditors JavaBeans. De nombreux PropertyEditors sont
fournis par défaut pour les types standards, mais vous pouvez créer le vôtre si nécessaire. Voir le
chapitre Propriétés dans la Partie II 'Développement de POJO' pour plus de détails.
3.5.2. Tester un service
Une fois que vous avez créé vos POJO et que vous les avez connecté pour former vos services, vous
aurez besoin de les tester. JBoss Microcontainer permet aux unités de tester les POJO individuels, ainsi
que les services, par l'utilisation d'une classe MicrocontainerT est.
\t\nLa classe org.jboss.test.kernel.junit.MicrocontainerT esthérite de
junit.fram ework.T estCase, configurant chaque test par un amorçage de JBoss Microcontainer et
en ajoutant un BasicXMLDeployer. Elle recherche alors le chemin de classe pour un descripteur de
déploiement de XML avec le même nom que la classe de test, se terminant par .xm l et résidant dans
21
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
une structure de répertoires qui représente le nom du package de la classe. Les beans qui se trouvent
dans ce fichier sont déployés et peuvent ensuite être consultés en utilisant une méthode pratique
appelée getBean(String nam e).
Vous pourrez trouver des descripteurs de déploiement dans Exemple 3.1, « Listing du répertoire
src/test/resources ».
Exemple 3.1. Listing du répertoire src/test/resources
├── log4j.properties
└── org
└── jboss
└── example
└── service
├── HRManagerAgeBasedTestCase.xml
├── HRManagerLocationBasedTestCase.xml
├── HRManagerTestCase.xml
└── util
├── AgeBasedSalaryTestCase.xml
└── LocationBasedSalaryTestCase.xml
Le code de test se situe dans le répertoire src/test/java :
Exemple 3.2. Listing du répertoire src/test/java
└── org
└── jboss
└── example
└── service
├── HRManagerAgeBasedTestCase.java
├── HRManagerLocationBasedTestCase.java
├── HRManagerTestCase.java
├── HRManagerTest.java
├── HRManagerTestSuite.java
└── util
├── AgeBasedSalaryTestCase.java
├── LocationBasedSalaryTestCase.java
└── SalaryStrategyTestSuite.java
\t\nLa classe HRManagerT est étend MicrocontainerT est afin d'installer un certain nombre
d'employés à utiliser comme base pour les tests, des cas de tests individuels, puis sous-classe
HRManagerT est, pour effectuer un travail réel. Quelques classes de T estSuite sont également
utilisées pour grouper des cas individuels de test pour l'aspect pratique.
Pour exécuter les tests, saisir m vn test à partir du répertoire hum anResourcesService/. Vous
devriez voir des sorties de log DEBUG qui montre que JBoss Microcontainerqui démarre et qui déploie
les beans du fichier XML qui convient, avant d'exécuter chaque test. En fin de tests, les beans ne sont
plus déployés et le Microcontainer est désactivé.
22
Chapitre 3. Services de construction
Note
Certains tests comme HRManagerT estCase, AgeBasedSalaryT estCase, et
LocationBasedSalaryT estCase, font des tests unitaires de POJO individuels. D'autres
tests comme HRManagerAgeBasedT estCase et HRManagerLocationBasedT estCase font
des tests unitaires de services entiers. Dans tous les cas, les tests sont exécutés de la même
manière. Utiliser la classe MicrocontainerT est facilite l'installation et la réalisation de tests en
profondeur de toute partie de votre code.
Les classes Address et Em ployee ne sont pas testées ici. C'est à vous d'écrire des tests pour
eux.
3.5.3. Packager un service
Après avoir testé votre service, il est temps de le mettre en paquet, afin que d'autres personnes
puissent l'utiliser. La façon la plus simple de le faire est de créer un JAR contenant toutes les classes.
Vous pouvez choisir d'inclure le descripteur de déploiement, s'il y a une bonne façon de configurer le
service par défaut, mais c'est optionnel.
Procédure 3.1. Mettre un service en package
1. Mettez le descripteur de déploiement dans le répertoire MET A-INF (en option).
Si vous choisissez d'inclure le descripteur de déploiement, par convention, il doit être nommé
jboss-beans.xm l et devra se trouver dans un répertoire MET A-INF. Il s'agit de la structure par
défaut pour Enterprise Platform, pour que le déployeur de JAR reconnaisse cette structure et
puisse effectuer le déploiement automatiquement.
Le descripteur de déploiement n'est pas inclus dans l'exemple de Ressources Humaines, parce
que le service est configuré en modifiant le descripteur directement, sous forme d'un fichier
séparé.
2. Générer le JAR
Pour générer un JAR qui contient toutes les classes compilées, saisir m vn package dans le
répertoire hum anResourcesService/.
3. Rendez le JAR disponible aux autres projets Maven.
Pour rendre le JAR disponible auprès des autres projets Maven, saisir m vn install pour le
copier dans votre référentiel Maven local. La structure finale du JAR se trouve dans Exemple 3.3,
« Listing of the org/jboss/exam ple/service and MET A-INFDirectories ».
23
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 3.3. Listing of the org/jboss/exam ple/service and MET A-INFDirectories
`-- org
`-- jboss
`-- example
`-- service
|-- Address.java
|-- Employee.java
|-- HRManager.java
`-- util
|-- AgeBasedSalaryStrategy.java
|-- LocationBasedSalaryStrategy.java
`-- SalaryStrategy.java
`--META-INF
`-- MANIFEST.MF
`-- maven
`-- org.jboss.micrcontainer.examples
`-- humanResourceService
Note
Le répertoire MET A-INF/m aven est créé automatiquement par Maven, et ne sera pas présent si
vous utilisez un autre système de construction.
24
Chapitre 4. Utiliser les services
Chapitre 4. Utiliser les services
Le chapitre précédent vous a guidé vers les création, configuration, test et mise en package d'un
service. La prochaine étape consiste à créer un client qui va en fait produire un travail en utilisant un
service.
Le client, dans cet exemple, utilise une interface T UI Text User Interface (TUI) pour accepter l'entrée de
l'utilisateur et les résultats de sortie. Cela réduit la taille et la complexité de l'exemple de code.
T ous les fichiers nécessaires sont situés dans le répertoire
exam ples/User_Guide/gettingstarted/com m andLineClient, qui suit le Maven Standard
Directory Layout, comme on le voit dans Exemple 4.1, « Listing pour le répertoire
exam ples/User_Guide/gettingstarted/com m andLineClient ».
Exemple 4 .1. Listing pour le répertoire
exam ples/User_Guide/gettingstarted/com m andLineClient
├──
├──
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
│
└──
pom.xml
src
├── main
│
├── assembly
│
│
├── aop.xml
│
│
├── classloader.xml
│
│
├── common.xml
│
│
└── pojo.xml
│
├── config
│
│
├── aop-beans.xml
│
│
├── classloader-beans.xml
│
│
├── pojo-beans.xml
│
│
└── run.sh
│
├── java
│
│
└── org
│
│
└── jboss
│
│
└── example
│
│
└── client
│
│
├── Client.java
│
│
├── ConsoleInput.java
│
│
├── EmbeddedBootstrap.java
│
│
└── UserInterface.java
│
└── resources
│
└── log4j.properties
└── test
├── java
│
└── org
│
└── jboss
│
└── example
│
└── client
│
├── ClientTestCase.java
│
├── ClientTestSuite.java
│
└── MockUserInterface.java
└── resources
└── jboss-beans.xml
target
└── classes
└── log4j.properties
Le client consiste en trois classes et une interface, qui se situent dans le répertoire
25
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
org/jboss/exam ple/client.\n
UserInterface décrit les méthodes appelées par le client en cours d'exécution pour demander des
actions de la part de l'utilisateur.ConsoleInput est une implémentation de UserInterface qui crée
un T UI utilisé par l'utilisateur pour communiquer avec le client. L'avantage de ce concept est que vous
pouvez facilement créer une implémentation Swing de UserInterface par la suite, et remplacer le T UI
par un GUI. Vous pouvez également simuler le processus de saisie des données par un script. Vous
pourrez alors vérifier le comportement des clients automatiquement par des cas de test JUnit
conventionnels que vous pourrez trouver dans Exemple 3.2, « Listing du répertoire src/test/java ».
Pour une génération réussie, vous devrez tout d'abord construire, et installer auditAspect.jar à
partir du répertoire exam ples/User_Guide/gettingStarted/auditAspect par le biais de la
commande m vn install com m and. Plusieurs distributions client seront créées, y compris une basée
AOP qui compte sur la présence de auditAspect.jar dans le répertoire Maven.
Si vous avez déjà saisi m vn install du répertoire exam ples/User_Guide/gettingStarted
alors hum anResourcesService.jar et auditAspect.jar auront déjà été générés et mis en
package, avec le client, donc cette étape ne sera pas nécessaire.
Pour compiler le code source, toutes les étapes de Procédure 4.1, « Compiler le Code Source » sont
franchies quand vous lancez la commande m vn package du répertoire com m andLineClient.
Procédure 4 .1. Compiler le Code Source
1. Exécuter les tests d'unités.
2. Générer un JAR client.
3. Assembler une distribution qui contient tous les fichiers utiles.
Après avoir compilé et empaqueté le client, la structure du répertoire dans le répertoire
com m andLineClient/target inclut les sous-répertoires décrits dans Exemple 4.2, « Sousrépertoires du répertoire com m andLineClient/target. ».
Exemple 4 .2. Sous-répertoires du répertoire com m andLineClient/target.
client-pojo
utilisé pour appeler le service sans AOP.
client-cl
utilisé pour démontrer les fonctionnalités de chargement de classes.
client-aop
Ajouter le support AOP. Voir Chapitre 5, Ajout de comportement AOP pour obtenir des détails
supplémentaires.
Chaque sous-répertoire représente une distribution différente, qui contient tous les scripts shell, les
JAR, et les descripteurs de déploiement XML utiles pour exécuter le client dans les configuraitons
variées. Le reste de ce chapitre est basé sur la distribution client-pojo que l'on toruve dans le
sous-répertoire client-pojo, listé dans Exemple 4.3, « Listing du répertoire client-pojo ».
26
Chapitre 4. Utiliser les services
Exemple 4 .3. Listing du répertoire client-pojo
|-|-|-|
|
|
|
|
|
|
|
|
|
|
|
`--
client-1.0.0.jar
jboss-beans.xml
lib
|-- concurrent-1.3.4.jar
|-- humanResourcesService-1.0.0.jar
|-- jboss-common-core-2.0.4.GA.jar
|-- jboss-common-core-2.2.1.GA.jar
|-- jboss-common-logging-log4j-2.0.4.GA.jar
|-- jboss-common-logging-spi-2.0.4.GA.jar
|-- jboss-container-2.0.0.Beta6.jar
|-- jboss-dependency-2.0.0.Beta6.jar
|-- jboss-kernel-2.0.0.Beta6.jar
|-- jbossxb-2.0.0.CR4.jar
|-- log4j-1.2.14.jar
`-- xercesImpl-2.7.1.jar
run.sh
Pour exécuter le client, déplacez-vous vers le répertoire client-pojo et saisissez ./run.sh.
Exemple 4.4, « Écran Menu HRManager » apparaîtra.
Exemple 4 .4 . Écran Menu HRManager
Menu:
d) Deploy Human Resources service
u) Undeploy Human Resources service
a)
l)
r)
g)
s)
t)
Add employee
List employees
Remove employee
Get a salary
Set a salary
Toggle hiring freeze
m) Display menu
p) Print service status
q) Quit
>
Pour sélectionner une option, saisir la lettre qui se situe sur la gauche et appuyer sur RET URN. Par
exemple, pour afficher les options du menu, saisir m , suivi par RET URN. Saisir plus d'une lettre ou saisir
une option qui n'est pas valide résultera par un message erreur.
27
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Important
Le script run.sh définit l'environnement d'exécution en ajoutant tous les JAR qui se trouvent
dans le répertoire lib/ dans le chemin de classes par la propriété java.ext.dirs. Il ajoute
également le répertoire courant et le client-1.0.0.jar par l'intermédiaire de l'indicateur -cp
de façon à ce que le descripteur de déploiement jboss-beans.xm l puisse être localisé en
cours d'exécution, ainsi que la classe org.jboss.exam ple.client.Client qui est appelée
pour démarrer l'application.
4.1. Amorçage de Microcontainer
Avant d'utiliser le client pour déployer et appeler votre service, regardez ce qui se passe quand il est
généré.
public Client(final boolean useBus) throws Exception {
this.useBus = useBus;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
url = cl.getResource("jboss-beans.xml");
// Start JBoss Microcontainer
bootstrap = new EmbeddedBootstrap();
bootstrap.run();
kernel = bootstrap.getKernel();
controller = kernel.getController();
bus = kernel.getBus();
}
T out d'abord un URL représentant le descripteur de déploiement jboss-beans.xm l est créé. Plus
tard, il sera nécessaire que le déployeur XML puisse déployer ou supprimer le déploiement des beans
déclarés dans le fichier. La méthode getResource() du chargeur de classes d'application est utilisée
parce que le fichier jboss-beans.xm l est inclus sur le chemin de classe. Cela est optionnel. Le nom
et la location du descripteur de déploiement importent peu tant que l'URL est valide et accessible.
Ensuite, une instance de JBoss Microcontanier est créée, avec un déployeur XML. Ce processus
s'appelle bootstrapping et une classe de convénience BasicBootstrap est fournie dans le
Microcontainer pour permettre la configuration programmatique. Pour ajouter un déployeur XML, étendre
BasicBootstrap pour créer une classe Em beddedBootstrap et remplacer la méthode
bootstrap() protégée comme suit :
28
Chapitre 4. Utiliser les services
public class EmbeddedBootstrap extends BasicBootstrap {
protected BasicXMLDeployer deployer;
public EmbeddedBootstrap() throws Exception {
super();
}
public void bootstrap() throws Throwable {
super.bootstrap();
deployer = new BasicXMLDeployer(getKernel());
Runtime.getRuntime().addShutdownHook(new Shutdown());
}
public void deploy(URL url) {
...
deployer.deploy(url);
...
}
public void undeploy(URL url) {
...
deployer.undeploy(url);
...
}
protected class Shutdown extends Thread {
public void run() {
log.info("Shutting down");
deployer.shutdown();
}
}
}
Le crochet shutdown veille qu'à la sortie de JVM, tous les déploiements de beans soient annulés dans
l'ordre qui convient. Les méthodes publiques deploy/undeploy délèguent au BasicXMLDeployer
de façon à ce que les beans déclarés dans jboss-beans.xm l puissent être déployés ou que leur
déploiement puisse être supprimé.
Finalement, les références au bus et au contrôleur du Microconteneur seront restaurées, donc vous
pourrez rechercher les références de bean par nom et y accéder directement ou indirectement si
nécessaire.
4.2. Déployer le service
Après avoir créé le service, vous pourrez déployer le service de Ressources Humaines. Vous pouvez
procéder en saisissant l'option d de l'interface utilisateur. La sortie indique que BasicXMLDeployer a
pu traiter le fichier jboss-beans.xm l par lURL, et en a instancié les beans.
29
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Note
Le Microconteneur est en mesure d'instancier les beans parce que leurs classes sont
disponibles dans l'extension du chemin de classe qui se trouve à l'intérieur du fichier
lib/hum anResourcesService.jar. Vous pouvez également mettre ces classes dans une
structure de répertoire explosée et l'ajouter au chemin de classe de l'application, mais il est plus
pratique de les mettre en paquet dans un JAR.
Le descripteur de déploiement est complètement séparé du fichier hum anResourcesService.jar.
Cela permet d'effectuer des changements rapides pour les tests. Le fichier jboss-beans.xm l de
l'exemple contient certains fragments de XML, dont les commentaires ont été supprimés, qui montrent
quelques unes des configurations possibles.
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
<bean name="HRService" class="org.jboss.example.service.HRManager">
<!-- <property name="hiringFreeze">true</property>
<property name="salaryStrategy"><inject bean="AgeBasedSalary"/></property> -->
</bean>
<!-- <bean name="AgeBasedSalary"
class="org.jboss.example.service.util.AgeBasedSalaryStrategy">
<property name="minSalary">1000</property>
<property name="maxSalary">80000</property>
</bean>
<bean name="LocationBasedSalary"
class="org.jboss.example.service.util.LocationBasedSalaryStrategy">
<property name="minSalary">2000</property>
<property name="maxSalary">90000</property>
</bean> -->
</deployment>
Important
Selon la façon dont vous accédez au service au moment de l'exécution, vous devrez peut-être
arrêter l'application et la redémarrez à nouveau pour redéployer le service et de voir vos
modifications. Cela réduit la flexibilité de l'application, mais résulte en une exécution plus rapide.
Alternativement, vous pourriez simplement redéployer le service en cours d'exécution de
l'application. Ceci accroît la flexibilité mais résulte en un ralentissement de la performance.
Gardez ces compromis en mémoire quand vous créez vos applications.
4.3. Accès direct
30
Chapitre 4. Utiliser les services
Si aucun paramètre n'est donné au script run.sh au démarrage du client, on cherche un bean
HRService par l'intermédiaire du contrôleur du Microconteneur, une fois que le service est déployé.
private HRManager manager;
...
private final static String HRSERVICE = "HRService";
...
void deploy() {
bootstrap.deploy(url);
if (!useBus && manager == null) {
ControllerContext context = controller.getInstalledContext(HRSERVICE);
if (context != null) { manager = (HRManager) context.getTarget(); }
}
}
Plutôt que de chercher tout de suite une référence pour l'instance de bean, l'exemple cherhce tout
d'abord une référence dans un ControllerContext, puis obtient une référence à l'instance de bean
à partir du contexte, en utilisant la méthode getT arget(). Be bean peut exister dans le Microcontainer
sous n'importe quel état listé dans État d'un bean à l'intérieur de Microcontainer.
État d'un bean à l'intérieur de Microcontainer
NOT _INST ALLED
DESCRIBED
INST ANT IAT ED
CONFIGURED
INST ALLED
T o keep track of which state the bean is in, wrap it in another object called a context that describes the
current state. T he name of the context is the same as the bean name. Once a context reaches the
INST ALLED state, the bean it represents is considered to be deployed.
After creating a reference to the bean instance representing the service entry point, you can call
methods on it to preform work:
@SuppressWarnings("unchecked")
Set<Employee> listEmployees() {
if (useBus)
...
else
return manager.getEmployees();
}
T he client is accessing the service directly since it is using a reference to the actual bean instance.
Performance is good, because each method call goes directly to the bean. What happens, however, if
31
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
you want to reconfigure the service and redeploy it while the application is running?
On obtient une reconfiguration en modifiant le descripteur de déploiement de XML et en enregistrant le
fichier. Afin de redéployer le service, l'instance actuelle doit être annulée. Lors de l'annulation du
déploiement, le contrôleur Microcontainer libère sa référence à l'instance de bean, ainsi que tous les
beans dépendantes. Ces beans pourront, par la suite, être nettoyés de la mémoire, parce qu'ils ne
soient plus requis par l'application. Redéployez le service crée de nouvelles instances de bean
représentant la nouvelle configuration. T oute recherche qui suivra, de la part des clients, permettra de
récupérer les références à ces nouvelles instances et ils seront en mesure d'accéder au service
reconfiguré.
Le problème, c'est que la référence à l'instance de bean représentant notre point d'entrée de service est
mis en cache lorsque vous déployez le service pour la première fois. L'annulation du déploiement du
service n'a aucun effet, puisque l'instance de bean peut toujours être accessible par la référence en
mémoire cache et ne sera pas nettoyée avant que le client la libère. Dans la même ligne, le déploiement
à nouveau du service n'entraîne pas une autre recherche parce que le client a déjà une référence en
mémoire cache. Il continuera donc à utiliser l'instance de bean représentant la configuration initiale de
service.
Vous pouvez tester ce comportement en saisissant la lettre u suivie par RET URN pour retirer le
déploiement du service en cours. Vous devez toujours pouvoir être en mesure d'accéder au service à
partir du client, même s'il n'est pas déployé. Puis, faîtes quelques changements à la configuration, en
utilisant le fichier jboss-beans.xm l, en l'enregistrant, et en le déployant à nouveau par l'option d.
Afficher le statut du service par l'option p montre que le client est toujours en train d'accéder à l'instance
initiale du service qui a été déployé.
Avertissement
Même si modifiez le client pour pouvoir rechercher une nouvelle référence à chaque fois que le
service est déployé à nouveau, les nouveaux développeurs peuvent distribuer des copies de
cette référence à d'autres objets, par erreur. Si ces références ne sont pas nettoyées pendant le
redéploiement, le même problème cache peut se reproduire.
Pour pouvoir redéployer le service reconfiguré de manière fiable, fermer l'application complètement par
l'option 'q' et redémarrer la par le script run.sh. Pour les services Enterprise comme T ransactions,
Messaging et Persistence, ce comportement est parfaitement acceptable, puisqu'ils sont généralement
toutjours utilisés. Ils ne peuvent pas être redéployés en cours d'exécution et peuvent bénéficier d'une
performance élevée par accès direct. Si votre service tombe dans cette catégorie, considérez l'accès
direct via le contrôleur de Microcontainer.
4.4. Accès indirect
Le script run.sh peut être appelé avec un paramètre en option bus, qui entraîne les appels au service
des Ressources Humaines à utiliser le bus du Microcontainer.
Au lieu d'utiliser une référence directe à l'instance de bean qui provient du contrôleur du Microcontainer,
le nouveau comportement consiste à appeler une méthodeinvoke() sur le bus, en lui passant le nom
du bean, le nom et arguments de la méthode, et les types de méthode. Le bus utilise cette information
pour appeler le bean de la part du client.
32
Chapitre 4. Utiliser les services
private final static String HRSERVICE = "HRService";
...
@SuppressWarnings("unchecked")
Set<Employee> listEmployees() {
if (useBus)
return (Set<Employee>) invoke(HRSERVICE, "getEmployees", new Object[] {},
new String[] {});
else
return manager.getEmployees();
}
private Object invoke(String serviceName, String methodName, Object[] args,
String[] types) {
Object result = null;
try {
result = bus.invoke(serviceName, methodName, args, types);
} catch (Throwable t) {
t.printStackTrace();
}
return result;
}
Le bus recherche la référence à l'instance de bean nommée et appelle la méthode choisie par réflexion.
Le client ne possède jamais une référence directe à l'instance de bean, donc on dit qu'il accède à la
fonction indirectement. Étant donné que le bus ne cache pas la référence, vous pouvez apporter des
modifications en toute sécurité à la configuration du service, et il peut être redéployé en cours
d'exécution. Les appels suivants par le client utiliseront la nouvelle référence, comme on s'y attend. Le
client et le service ont été découplés.
Note
Ce comportement peut être testé en déployant le service et en utilisant l'option p pour imprimer le
statut. Retirer le déploiement sur le service en utilisant l'option u et vous remarquerez qu'il n'est
pas accessible. Puis, procédez à quelques changements au fichier jboss-beans.xm l,
enregistrez les changements, et déployez-le à nouveau avec l'option d. IAfficher le statut à
nouveau par l'option p. Le client aura accès à la nouvelle configuration du service.
Comme le bus utilise la réflexion pour appeler des instances de bean, c'est plus lent que l'accès direct.
L'avantage de l'approche, c'est que seul le bus possède des références aux instances bean. Lorsqu'un
service est redéployé, toutes les références existantes peuvent être nettoyées et remplacées par de
nouvelles. De cette façon, un service peut être redéployé de façon fiable en cours d'exécution. Les
services qui ne sont pas très souvent utilisés ou qui sont spécifiques à certaines applications sont
bons candidats à l'accès indirect par le bus du Microcontainer. Souvent, la réduction des performances
est supplantée par l'avantage de la souplesse.
4.5. Le chargement de classes dynamique
Jusqu'à ce point, vous avez utilisé l'extension et les chargeurs de classe de l'application pour charger
toutes les classes de l'application. Le chemin de classe de l'application est défini par le script run.sh
avec l'indicateur -cp pour inclure le répertoire courant dans client-1.0.0.jar, comme montré ici :
33
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
java -Djava.ext.dirs=`pwd`/lib -cp .:client-1.0.0.jar
org.jboss.example.client.Client $1
Pour plus de commodité, les JAR du répertoire lib ont été ajoutés au chemin de classe de l'extension
du chargeur de classes, à l'aide de la propriété de système java.ext.dirs, plutôt que de lister le chemin
d'accès complet vers chacun des JAR après l'indicateur -cp. Comme l'extension de classloader est
parente de l'application classloader, le client est est mesure de trouver toutes les classes du
Microconteneur et du service des Ressources Humaines en cours d'exécution.
Note
Dans les versions Java 6 et versions supérieures, vous pouvez utiliser une expression de
caractère générique pour inclure tous les JAR dans un répertoire par l'indicateur -cp: java -cp
`pwd`/lib/* :.:client-1.0.0.jar org.jboss.exam ple.client.Client $1
Ici, toutes les classes de l'application seront ajoutées au chemin de classe du chargeur de
classes d'application, et le chemin de classe de l'extension du chargeur de classes conservera
sa valeur par défaut.
What happens if you need to deploy an additional service at run-time? If the new service is packaged in
a JAR file, it must be visible to a classloader before any of its classes can be loaded. Because you have
already set up the classpath for the application classloader (and extension classloader) on start-up, it is
not easy to add the URL of the JAR. T he same situation applies if the service classes are contained in a
directory structure. Unless the top-level directory is located in the current directory (which is on the
application classpath) then the classes will not be found by the application classloader.
If you wish to redeploy an existing service, changing some of its classes, you need to work around
security constraints, which forbid an existing classloader from reloading classes.
T he goal is to create a new classloader that knows the location of the new service's classes, or that can
load new versions of an existing service's classes, in order to deploy the service's beans. JBoss
Microcontainer uses the <classloader> element in the deployment descriptor to accomplish this.
T he client-cl distribution contains the file listed in the Exemple 4.5, « Listing of the
com m andLineClient/target/client-cl Directory » .
34
Chapitre 4. Utiliser les services
Exemple 4 .5. Listing of the com m andLineClient/target/client-cl Directory
|-- client-1.0.0.jar
|-- jboss-beans.xml
|-- lib
|
|-- concurrent-1.3.4.jar
|
|-- jboss-common-core-2.0.4.GA.jar
|
|-- jboss-common-core-2.2.1.GA.jar
|
|-- jboss-common-logging-log4j-2.0.4.GA.jar
|
|-- jboss-common-logging-spi-2.0.4.GA.jar
|
|-- jboss-container-2.0.0.Beta6.jar
|
|-- jboss-dependency-2.0.0.Beta6.jar
|
|-- jboss-kernel-2.0.0.Beta6.jar
|
|-- jbossxb-2.0.0.CR4.jar
|
|-- log4j-1.2.14.jar
|
`-- xercesImpl-2.7.1.jar
|-- otherLib
|
`-- humanResourcesService-1.0.0.jar
|`-- run.sh
T he hum anResourcesService.jar file has been moved to a new sub-directory called otherLib. It
is no longer available to either the extension or application classloaders whose classpaths are setup in
the run.sh script:
java -Djava.ext.dirs=`pwd`/lib -cp .:client-1.0.0.jar
org.jboss.example.client.Client $1
T o work around this, create a new classloader during the deployment of the service, load it in the service
classes, and create instances of the beans. T o see how this is done, look at the contents of the jbossbeans.xm l file:
35
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
<bean name="URL" class="java.net.URL">
<constructor>
<parameter>file:/Users/newtonm/jbossmc/microcontainer/trunk/docs/examples/User_Gui
de/gettingStarted/commandLineClient/target/clientcl.dir/otherLib/humanResourcesService-1.0.0.jar</parameter>
</constructor>
</bean>
<bean name="customCL" class="java.net.URLClassLoader">
<constructor>
<parameter>
<array>
<inject bean="URL"/>
</array>
</parameter>
</constructor>
</bean>
<bean name="HRService" class="org.jboss.example.service.HRManager">
<classloader><inject bean="customCL"/></classloader>
<!-- <property name="hiringFreeze">true</property>
<property name="salaryStrategy"><inject bean="AgeBasedSalary"/></property> -->
</bean>
<!-- <bean name="AgeBasedSalary"
class="org.jboss.example.service.util.AgeBasedSalaryStrategy">
<property name="minSalary">1000</property>
<property name="maxSalary">80000</property>
</bean>
<bean name="LocationBasedSalary"
class="org.jboss.example.service.util.LocationBasedSalaryStrategy">
<property name="minSalary">2000</property>
<property name="maxSalary">90000</property>
</bean> -->
</deployment>
1. First, create an instance of java.net.URL called URL, using parameter injection in the
constructor to specify the location of the hum anResourcesService.jar file on the local filesystem.
2. Next, create an instance of a URLClassLoader by injecting the URL bean into the constructor as
the only element in an array.
3. Include a <classloader> element in your HRService bean definition and inject the custom CL
bean. T his specifies that the HRManager class needs to be loaded by the customCL classloader.
You need a way to decide which classloader to use for the other beans in the deployment. All beans in
36
Chapitre 4. Utiliser les services
the deployment use the current thread's context classloader. In this case the thread that handles
deployment is the main thread of the application which has its context classloader set to the application
classloader on start-up. If you wish, you can specify a different classloader for the entire deployment
using a <classloader> element, as shown in Exemple 4.6, « Specifying a Different Classloader ».
Exemple 4 .6. Specifying a Different Classloader
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
<classloader><inject bean="customCL"/></classloader>
<bean name="URL" class="java.net.URL">
<constructor>
<parameter>file:/Users/newtonm/jbossmc/microcontainer/trunk/docs/examples/User_G
uide/gettingStarted/commandLineClient/target/clientcl.dir/otherLib/humanResourcesService-1.0.0.jar</parameter>
</constructor>
</bean>
<bean name="customCL" class="java.net.URLClassLoader">
<constructor>
<parameter>
<array>
<inject bean="URL"/>
</array>
</parameter>
</constructor>
</bean>
...
</deployment>
T his would be necessary to allow for reconfiguration of the service by uncommenting the
AgeBasedSalary or LocationBasedSalary beans. Classloaders specified at the bean level
override the deployment level classloader. T o override the deployment level classloader altogether, and
use the default classloader for a bean, use the <null/> value as follows:
<bean name="HRService" class="org.jboss.example.service.HRManager">
<classloader><null/></classloader>
</bean>
37
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
4.5.1. Problems With Classloaders Created with Deployment Descriptors
If you create a new classloader for your service using the deployment descriptor, you may not be able to
access classes loaded by it from the application classloader. In the HRManager example, the client is no
longer able to cache a direct reference to the bean instance when using the Microcontainer controller.
T o see this behavior, start the client using the run.sh command, then try to deploy the service. A
java.lang.NoClassDefFoundError exception is thrown and the application exits.
In this scenario, you must use the bus to access the service indirectly and provide access to any
classes shared by the client in the application classpath. In this example, the affected classes are
Address, Em ployee, and SalaryStrategy.
38
Chapitre 5. Ajout de comportement AOP
Chapitre 5. Ajout de comportement AOP
L'OOP (Object Oriented Programming / Programmation Orientée Objet) contient de nombreuses
techniques utiles pour le développement de logiciels, y compris l'encapsulation, l'héritage et le
polymorphisme. T outefois, elle ne résout pas le problème de la logique souvent répétée dans
différentes classes, par exemple, la logique transactionnelle, d'enregistrement, ou de sécurité qui sont
traditionnellement codées en dur dans chaque classe. Ce type de logique est appelé cross-cutting
concern (préoccupations intersectorielles).
Aspect Oriented Programming (AOP) permet aux cross-cutting concerns d'être appliquées aux classes
après qu'elles aient été compilées. Cela permet au code source de demeurer départi de la logique qui
n'est pas essentielle à l'objet principal de la classe et qui simplifie la maintenance. La méthode dépend
de la mise en œuvre de l'AOP. Si une classe implémente une interface, chaque appel de méthode à une
instance de la classe passe d'abord via un proxy. Ce proxy implémente la même interface, ajoutant le
comportement requis. Alternativement, si une interface n'est pas utilisée, alors le bytecode Java de la
classe compilée sera modifié : les méthodes originales seront renommées et remplacées par des
méthodes qui implémentent la logique transversale. Ces nouvelles méthodes appellent ensuite les
méthodes originales après que la logique transversale ait été exécutée. Une autre méthode pour obtenir
le même résultat consiste à modifier le bytecode pour créer une sous-classe de la classe d'origine qui
remplace ses méthodes. Les méthodes substituées exécutent alors la logique transversale avant
d'appeler les méthodes correspondantes de la super classe.
JBoss AOP est une structure pour l'AOP. En l'utilisant, vous pouvez créer des cross-cutting concerns à
l'aide de méthodes et classes java classiques. Dans la terminologie de l'AOP chaque préoccupation
(concern) est représentée par un aspect que vous pouvez implémenter à l'aide d'un simple POJO. Ce
comportement est fourni par des méthodes qui se trouvent à l'intérieur de l'aspect, et qui s'appellent des
advices (conseils). Ces conseils suivent certaines règles de paramétrage et retournent les types et
exceptions qu'ils soulèvent. Sur la base de cette structure, vous pouvez utiliser des notions
conventionnelles orientées-objet comme l'héritage, l'encapsulation et la composition pour faciliter la
maintenance de vos cross-cutting concerns. Les aspects sont appliquées au code à l'aide d'un langage
d'expression qui vous permet d'indiquer les constructeurs, les méthodes et les même les champs à
cibler. Vous pouvez rapidement modifier le comportement des classes multiples en éditant un fichier de
configuration.
Ce chapitre contient des exemples qui démontrent comment utiliser JBoss AOP avec le Microcontainer
pour créer et pour appliquer un aspect d'audit du Service des ressources humaines. Le code d'audit
devra se situer dans la classe HRManager, mais il encombrerait la classe avec le code qui n'est pas
central et compliquerait la maintenance. Le design de l'aspect fournit également une certaine modularité,
ce qui faciliters les audits de classe à venir, si la portée du projet venait à changer.
AOP peut également être utilisé pour faire appliquer des comportement supplémentaires en cours de
déploiement. Cet exemple va créer et relier un proxy à une instance de bean dans un service de base
JNDI, lui permettant ainsi d'accéder à une recherche de JNDI plutôt qu'à un contrôleur de Microcontainer.
5.1. Créer un aspect
Le répertoire exam ples/User_Guide/gettingStarted/auditAspect contient tous les fichiers
utiles pour créer l'aspect.
pom .xm l
src/m ain/java/org/jboss/exam ple/aspect/AuditAspect.java
39
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 5.1. Exemple de POJO
public class AuditAspect {
private String logDir;
private BufferedWriter out;
public AuditAspect() {
logDir = System.getProperty("user.dir") + "/log";
File directory = new File(logDir);
if (!directory.exists()) {
directory.mkdir();
}
}
public Object audit(ConstructorInvocation inv) throws Throwable {
SimpleDateFormat formatter = new SimpleDateFormat("ddMMyyyy-kkmmss");
Calendar now = Calendar.getInstance();
String filename = "auditLog-" + formatter.format(now.getTime());
File auditLog = new File(logDir + "/" + filename);
auditLog.createNewFile();
out = new BufferedWriter(new FileWriter(auditLog));
return inv.invokeNext();
}
public Object audit(MethodInvocation inv) throws Throwable {
String name = inv.getMethod().getName();
Object[] args = inv.getArguments();
Object retVal = inv.invokeNext();
StringBuffer buffer = new StringBuffer();
for (int i=0; i < args.length; i++) {
if (i > 0) {
buffer.append(", ");
}
buffer.append(args[i].toString());
}
if (out != null) {
out.write("Method: " + name);
if (buffer.length() > 0) {
out.write(" Args: " + buffer.toString());
}
if (retVal != null) {
out.write(" Return: " + retVal.toString());
}
out.write("\n");
out.flush();
}
return retVal;
}
}
40
Chapitre 5. Ajout de comportement AOP
Procédure 5.1. Créer le POJO
1. Le constructeur contrôle la présence d'un répertoire log dans le répertoire de travail en cours, et
en crée un s'il n'existe pas.
2. Ensuite, on définit un conseil. Ce conseil est appelé à chaque fois que le constructeur de la
classe cible est appelé. Cela crée un nouveau fichier de journalisation dans le répertoire log
pour enregistrer les appels de méthode faits sur diverses instances de la classe cible dans des
fichiers séparés.
3. Finalement, on définit un autre conseil. Ce conseil s'applique à tout appel de méthode fait sur la
classe cible. Le nom de la méthode et les arguments sont stockés, ainsi que la valeur de retour.
Cette information est utilisée pour construire une archive d'audit et l'inscrire dans le fichier de
journalisation courant. Chaque conseil appelle inv.invokeNext(), qui enchaîne les conseils
ensemble plus d'un cross-cutting concern a été appliqué, ou pour appeler la méthode/le
construteur de la cible.
Note
Chaque conseil est utilisé avec une méthode qui prend un objet d'invocation comme paramètre,
lance T hrowable et renvoie Object. Au moment de le leur conception, vous ne savez pas à quel
constructeur ou méthode ces conseils vont s'appliquer, donc rendez les aussi généraux que
possible.
Pour compiler la classe et créer un fichier auditAspect.jar qui puissent être utilisé par d'autres
exemples, taper m vn install à partir du répertoire auditAspect.
5.2. Configurer le Microcontainer pour AOP
Avant d'appliquer l'aspect audit au service HR (RU / Ressources humaines), vous devrez ajouter un
certain nombre de JAR au chemin de classe d'extension. Ils se trouvent dans le sous-répertoire lib de
la distribution client-aop qui se trouve dans le répertoire
exam ples/User_Guide/gettingStarted/com m andLineClient/target/client-aop.dir :
41
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 5.2. Listing du répertoire
examples/User_Guide/gettingStarted/commandLineClient/target/client-aop.dir
|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-`-|-`-`--
client-1.0.0.jar
jboss-beans.xml
lib
auditAspect-1.0.0.jar
concurrent-1.3.4.jar
humanResourcesService-1.0.0.jar
javassist-3.6.0.GA.jar
jboss-aop-2.0.0.beta1.jar
jboss-aop-mc-int-2.0.0.Beta6.jar
jboss-common-core-2.0.4.GA.jar
jboss-common-core-2.2.1.GA.jar
jboss-common-logging-log4j-2.0.4.GA.jar
jboss-common-logging-spi-2.0.4.GA.jar
jboss-container-2.0.0.Beta6.jar
jboss-dependency-2.0.0.Beta6.jar
jboss-kernel-2.0.0.Beta6.jar
jbossxb-2.0.0.CR4.jar
log4j-1.2.14.jar
trove-2.1.1.jar
xercesImpl-2.7.1.jar
log
auditLog-18062010-122537
run.sh
T out d'abord, lib/auditAspect-1.0.0.jar est nécessaire pour créer une instance de l'aspect au
moment de l'exécution, afin d'exécuter la logique. Ensuite le fichier jar pour JBoss AOP (jboss-aop.jar),
avec ses dépendances javassist et trove, ajoute la fonctionnalité AOP. Enfin, le jar jboss-aop-mc-int est
nécessaire parce qu'il contient une définition de schéma XML qui permet de définir les aspects à
l'intérieur d'un descripteur de déploiement XML. Il contient également un code d'intégration pour créer
des dépendances entre les beans normaux et beans aspect au sein du Microcontainer, vous permettant
d'ajouter un comportement durant les phases de déploiement et d'annulation de déploiement.
Comme vous utilisez Maven2 pour assembler la distribution client-aop, vous devez ajouter ces fichiers
JAR en déclarant les dépendances qui conviennent dans votre fichier pom .xm l et en créant un
descripteur d'assembly valide. Vous trouverez un extrait de pom .xm l dans Exemple 5.3, « Example
d'extrait pom .xm l pour AOP ».
42
Chapitre 5. Ajout de comportement AOP
Exemple 5.3. Example d'extrait pom .xm l pour AOP
<dependency>
<groupId>org.jboss.microcontainer.examples</groupId>
<artifactId>jboss-oap</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.jboss.microcontainer.examples</groupId>
<artifactId>javassist</artifactId>
<version>3.6.0.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.microcontainer.examples</groupId>
<artifactId>trove</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.jboss.microcontainer.examples</groupId>
<artifactId>jboss-aop-mc-int</artifactId>
<version>2.0.0.Beta6</version>
</dependency>
5.3. Appliquer un Aspect
Maintenant que vous avez une distribution valide qui contient tout ce dont vous avez besoin, vous
pouvez configurer jboss-beans.xm l pour appliquer l'aspect audit. Il se situe dans
exam ples/User_Guide/gettingStarted/com m andLineClient/target/client-aop.dir.
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
<bean name="AspectManager" class="org.jboss.aop.AspectManager">
<constructor factoryClass="org.jboss.aop.AspectManager"
factoryMethod="instance"/>
</bean>
<aop:aspect xmlns:aop="urn:jboss:aop-beans:1.0"
name="AuditAspect" class="org.jboss.example.aspect.AuditAspect"
method="audit" pointcut="execution(public
org.jboss.example.service.HRManager->new(..)) OR
execution(public * org.jboss.example.service.HRManager->*(..))">
</aop:aspect>
...
</deployment>
43
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Procédure 5.2. Explication du code d'application d'Aspect
1. Avant d'appliquer votre aspect à une classe, vous aurez besoin de créer une instance de
org.jboss.aop.AspectManager en utilisant un élément <bean>. On utilise ici une méthode
d'usine au lieu d'utiliser un constructeur conventionnel, puisqu'on a besoin d'une seule instance
d'AspectManager dans la JVM en cours d'exécution.
2. Ensuite, une instance de l'aspect AuditAspect est créée, en utilisant l'élément <aop:aspect>. Cela
ressemble à l'élément <bean> puisqu'elle a des attributs name et class qui sont utilisés de la
même façon. Aussi, elle possède les attributs method et pointcut que vous pouvez utiliser pour
appliquer ou pour relier un conseil à des constructeurs ou à des méthodes dans d'autres
classes. Ces attributs relient le conseil audit à tous les constructeurs ou méthodes de la classe
HRManager. Seule la méthode audit a besoin d'être spécifiée, puisqu'elle n'a pas été
surchargée par différents paramètres dans la classe AuditAspect. En cours d'exécution, JBoss
AOP sait quoi sélectionner, suivant qu'il s'agisse d'un constructeur ou d'un invocation de
méthode.
Cette configuration supplémentaire est tout ce dont vous avez besoin pour pouvoir faire appliquer
l'aspect audit en cours d'exécution, ajoutant ainsi un comportement au service Human Resources.
Vous pouvez tester en exécutant le client par le script run.sh. Quand le bean AuditAspect est créé
par le Microcontainer, un répertoire log est créé au démarrage en même temps que le répertoire lib.
Chaque déploiement du service de ressources humaines fait apparaître un nouveau fichier de
journalisation dans le répertoire log. Le fichier de journalisation contient un enregistrement de tout
appel du client au service. Il est nommé quelque chose du style auditLog-28112007-163902, et
contient des sorties du style Exemple 5.4, « Exemple de sortie le Log AOP ».
Exemple 5.4 . Exemple de sortie le Log AOP
Method: getEmployees Return: []
Method: addEmployee Args: (Santa Claus, 1 Reindeer Avenue, Lapland City
- 25/12/1860) Return: true
Method: getSalary Args: (Santa Claus, null - Birth date unknown) Return:
10000
Method: getEmployees Return: [(Santa Claus, 1 Reindeer Avenue, Lapland
City - 25/12/1860)]
Method: isHiringFreeze Return: false
Method: getEmployees Return: [(Santa Claus, 1 Reindeer Avenue, Lapland
City - 25/12/1860)]
Method: getSalaryStrategy
Pour retirer le comportement d'audit, retirer les fragments XML concernés du descripteur de
déploiement, et redémarrer l'application.
Avertissement
L'ordre de déploiement est important. Chaque aspect doit être déclaré spécifiquement pour les
beans auxquels il s'applique, pour le le Microcontainer puisse les déployer dans cet ordre. C'est
parce que le Microcontainer a sans doute besoin de modifier le bytecode de la classe de bean
normale pour ajouter la logique transversale, avant de créer une instance et stocker en créer une
référence dans le contrôleur. Cela n'est pas possible si une instance normale de bean a déjà été
créée.
44
Chapitre 5. Ajout de comportement AOP
5.4. Lifecycle Callbacks
En plus d'appliquer des aspects à des beans que l'on instancie par le Microcontainer, nous pouvons
également ajouter un comportement au cours du processus de déploiement ou de retrait du
déploiement. Comme noté dans Section 4.3, « Accès direct », un bean passe par différents états en
cours de déploiement. Ces états incluent :
NOT _INST ALLED
le descripteur de déploiement qui contient le bean a été traité, ainsi que toute annotation qui se
trouve sur le bean.
DESCRIBED
toute dépendance créée par AOP ont été ajoutées au bean, et les annotations personnalisées
ont été traitées.
INST ANT IAT ED
une instance de bean a été créée.
CONFIGURED
les propriétés ont été injectées dans le bean, ainsi que toute référence aux autres beans.
CREAT E
la méthode create, à condition qu'elle ait été définie dans le bean, est appelée.
ST ART
la méthode start, à condition qu'elle ait été définie dans le bean, est appelée.
INST ALLED
toutes les actions d'installation personnalisées qui ont été définies dans le descripteur de
déploiement ont été exécutées et le bean est prêt à l'accès.
Important
Les états CREAT E et ST ART sont inclus pour des questions d'héritage. Cela permet aux services
qui étaient implémentés comme MBeans dans les versions antérieures d'Enterprise Platform de
fonctionner correctement quand ils sont implémentés en tant que beans dans Enterprise Platform
5.1. Si vous ne définissez pas de méthode create/start correspondante dans votre bean, il
passera directement à travers ces états.
Ces états représentent le cycle de vie du bean. Vous pouvez définir un certain nombre de callbacks qui
peuvent s'appliquer à n'importe quel point, en utilisant un groupe d'éléments <aop> séparé :
<aop:lifecycle-describe>
s'applique quand on entre/sort de l'état DÉCRIT
45
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
<aop:lifecycle-instantiate>
s'applique quand on entre/sort de l'état INST ANCIÉ
<aop:lifecycle-configure>
s'applique quand on entre/sort de l'état CONFIGURÉ
<aop:lifecycle-create>
s'applique quand on entre/sort de l'état CRÉER
<aop:lifecycle-start>
s'applique quand on entre/sort de l'état ST ART
<aop:lifecycle-install>
s'applique quand on entre/sort de l'état INST ALLÉ
T out comme les éléments <bean> et <aop:aspect>, les éléments <aop:lifecycle-> contiennent des
attributs name et class. Le Microcontainer utilise ces attributs pour créer une instance de la classe
callback, en la nommant pour qu'elle puisse être utilisée au fur et à mesure que les beans entrent ou
sortent d'un état particulier en cours de déploiement ou en cours de retrait de déploiement. Vous
pourrez spécifier quels beans sont affectés par le callack en utilisant l'attribut de classe, comme le
montre Exemple 5.5, « Utilisation de l'attribut classes ».
Exemple 5.5. Utilisation de l'attribut classes
<aop:lifecycle-install xmlns:aop="urn:jboss:aop-beans:1.0"
name="InstallAdvice"
class="org.jboss.test.microcontainer.support.LifecycleCallback"
classes="@org.jboss.test.microcontainer.support.Install">
</aop:lifecycle-install>
Ce code précise qu'une logique supplémentaire de la classe lifecycleCallback a été appliquée à
toute classe de bean annotée par @org.jboss.test.microcontainer.support.Install avant
d'entrer ou de quitter l'état INST ALLED.
Pour que la classe de callback fonctionne, elle doit contenir les méthodes install et uninstall qui
prennent ControllerContext comme paramètre, comme dans Exemple 5.6, « Méthodes d'installation
et de désinstallation ».
46
Chapitre 5. Ajout de comportement AOP
Exemple 5.6. Méthodes d'installation et de désinstallation
import org.jboss.dependency.spi.ControllerContext;
public class LifecycleCallback {
public void install(ControllerContext ctx) {
System.out.println("Bean " + ctx.getName() + " is being installed";
}
public void uninstall(ControllerContext ctx) {
System.out.println("Bean " + ctx.getName() + " is being uninstalled";
}
}
La méthode install est appelée au cours du déploiement du bean, et la méthode uninstall est
appelée en cours de retrait du déploiement.
Note
Bien que les callbacks rajoutent du comportement aux processus de déploiement et de retrait de
déploiement, AOP n'est pas utilisé dans ces cas. La fonctionnalité pointcut expression de JBoss
AOP est utilisée pour déterminer à quelles classes de bean les comportements s'appliquent.
5.5. Ajout de Recherche de service (Look-ups) par JNDI
Jusqu'à présent, vous avez utilisé le Microcontainer pour chercher des références d'instances de beans
qui représentent des services. Ce n'est pas l'idéal, parce que vous avez besoin d'une référence au
noyau du Micro container avant d'accéder du contrôleur. Vous pourrez voir cela dans Exemple 5.7,
« Rechercher des références de Beans ».
47
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 5.7. Rechercher des références de Beans
private
private
private
private
private
HRManager manager;
EmbeddedBootstrap bootstrap;
Kernel kernel;
KernelController controller;
final static String HRSERVICE = "HRService";
...
// Start JBoss Microcontainer
bootstrap = new EmbeddedBootstrap();
bootstrap.run();
kernel = bootstrap.getKernel();
controller = kernel.getController();
...
ControllerContext context = controller.getInstalledContext(HRSERVICE);
if (context != null) { manager = (HRManager) context.getTarget(); }
Donner des références de noyau à tous les clients qui recherchent un service présente un risque de
sécurité, parce que cela donne accès général à la configuration du Microcontainer. Pour une meilleure
sécurité, appliquer le modèle ServiceLocator et utiliser une classe pour pouvoir effectuer les recherches
pour le compte des clients. Mieux encore, passez les références de beans, ainsi que leur nom, au
ServiceLocator au moment du déploiement, en utilisant un callback de cycle de vie. Dans un tel scénario,
le ServiceLocator peut les chercher sans être au courant du Microcontainer. Le retrait du déploiement
retirerait par conséquence les références de bean du ServiceLocator pour éviter toute recherche
supplémentaire.
Il n'est pas difficile d'écrire votre propre implémentation de ServiceLocator. En intégrer une comme JBoss
Naming Service (JBoss NS) est même plus rapide, et a comme avantage supplémentaire d'être en
accord avec la norme JNDI (Java Naming and DIrectory Interface). JNDI permet aux clients d'accéder à
plusieurs, peut-être multiples services de nommage en utilisant un API en commun.
Procédure 5.3. Rédiger votre propre implémentation de ServiceLocator
1. T out d'abord, créer une instance de JBoss NS en utilisant le Microcontainer.
2. Puis, ajouter un callback de cycle de vie pour procéder à la liaison ou séparation des références
de bean pendant le déploiement ou son retrait.
3. Marquez les classes de bean pour lesquelles vous souhaitez relier des références, en utilisant
des annotations.
4. Maintenant, vous pouvez localiser les beans en cours d'exécution grâce à l'expression pointcut
raccourcie, comme montré plus haut.
48
Partie II. Concepts avancés de Microcontainer
Partie II. Concepts avancés de Microcontainer
Cette section couvre des concepts avancés, et montrent quelques fonctionnalités intéressantes du
Microcontainer. On assume que les exemples de code qui se trouvent dans le reste du guide sont des
exemples incomplets, et que c'est la responsabilité du programmeur de les extrapoler ou de les étendre,
suivant les besoins.
49
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Chapitre 6. Modèles de composants
JBoss Microcontainer fonctionne avec plusieurs modèles de composants POJO connus. Les
composants sont des programmes de logiciels réutilisables que vous pouvez développer et assembler
facilement pour créer des applications sophistiquées. L'intégration effective de ces modèles de
composants était le but principal du Microcontainer. JMX, Spring et Guice sont des modèles de
composants populaires utilisables avec Microcontainer.
6.1. Interactions permises avec les modèles de composants
Avant de discuter l'interaction avec certains des modèles de composants les plus populaires, il faut bien
comprendre quels types d'interaction sont permis. JMX MBeans représentent un exemple de modèle de
composant. Leurs interactions s'étendent aux opérations MBean, le référencement des attributs, la
configuration des attributs, et la déclaration des dépendances explicites entres les MBeans nommés.
Les interactions et comportements par défaut de Microcontainer sont les mêmes que n'importe quel
autre conteneur Inversion of Control (IoC) et ressemblent à la fonctionnalité fournie par MBeans, y
compris les invocations de méthodes pleines pour les opérations, les setters/getters pour les attributs
et dépendances explicites.
6.2. Un bean sans dépendances
Exemple 6.1, « Descripteur de déploiement pour un POJO simple. » montre un descripteur de
déploiement pour un POJO simple sans dépendance. Il s'agit du point de départ pour intégrer le
Microcontainer avec Spring ou Guice.
Exemple 6.1. Descripteur de déploiement pour un POJO simple.
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="PlainPojo" class="org.jboss.demos.models.plain.Pojo"/>
<beanfactory name="PojoFactory" class="org.jboss.demos.models.plain.Pojo">
<property
name="factoryClass">org.jboss.demos.models.plain.PojoFactory</property>
</beanfactory>
</deployment>
6.3. Utilisation de Microcontainer avec Spring
50
Chapitre 6. Modèles de composants
Exemple 6.2. Descripteur avec Support Spring
<beans xmlns="urn:jboss:spring-beans:2.0">
<!-- Adding @Spring annotation handler -->
<bean id="SpringAnnotationPlugin"
class="org.jboss.spring.annotations.SpringBeanAnnotationPlugin" />
<bean id="SpringPojo" class="org.jboss.demos.models.spring.Pojo"/>
</beans>
L'espace-nom du fichier est différent du fichier de bean du Microcontainer simple. L'espace-nom de
urn:jboss:spring-beans:2.0 pointe vers votre version du port de schéma Spring, qui décrit le
style Spring de votre bean. Le Microcontainer, et non pas la notion d'usine de bean de Spring, déploie
le bean.
Exemple 6.3. Utilisation de Spring avec le Microcontainer
public class Pojo extends AbstractPojo implements BeanNameAware {
private String beanName;
public void setBeanName(String name)
{
beanName = name;
}
public String getBeanName()
{
return beanName;
}
public void start()
{
if ("SpringPojo".equals(getBeanName()) == false)
throw new IllegalArgumentException("Name doesn't match: " + getBeanName());
}
}
Malgré que le bean SpringPojo ait une dépendance dans la bibliothèque de Spring causée par
l'implémentation de l'interface BeanNameAware, son seul but est d'exposer le comportement callback
de Spring.
51
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Le focus de Guice est de faire correspondre les types. Les beans Guice sont générés et configurés en
utilisant des modules.
Exemple 6.4 . Le descripteur de déploiement d'intégration de Guice dans le
Microcontainer
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="GuicePlugin"
class="org.jboss.guice.spi.GuiceKernelRegistryEntryPlugin">
<constructor>
<parameter>
<array elementClass="com.google.inject.Module">
<bean class="org.jboss.demos.models.guice.PojoModule"/>
</array>
</parameter>
</constructor>
</bean>
</deployment>
Les parties importantes à observer dans ce fichier sont PojoModule et
GuiceKernelRegistryEntryPlugin. PojoModule configure vos beans, comme dans Exemple 6.5,
« Configurer les beans pour Guice ». GuiceKernelRegistryEntryPlugin fournit l'intégration dans
Microcontainer, comme le montre Exemple 6.6, « Intégration de Guice dans Microconteneur ».
52
Chapitre 6. Modèles de composants
Exemple 6.6. Intégration de Guice dans Microconteneur
public class GuiceKernelRegistryEntryPlugin implements KernelRegistryPlugin {
private Injector injector;
public GuiceKernelRegistryEntryPlugin(Module... modules)
{
injector = Guice.createInjector(modules);
}
public void destroy()
{
injector = null;
}
public KernelRegistryEntry getEntry(Object name)
{
KernelRegistryEntry entry = null;
try
{
if (name instanceof Class<?>)
{
Class<?> clazz = (Class<?>)name;
entry = new AbstractKernelRegistryEntry(name, injector.getInstance(clazz));
}
else if (name instanceof Key)
{
Key<?> key = (Key<?>)name;
entry = new AbstractKernelRegistryEntry(name, injector.getInstance(key));
}
}
catch (Exception ignored)
{
}
return entry;
}
}
Note
Injector est créé à partir de la classe Modules, puis il recherche les beans qui
correspondent. Voir Section 6.5, « Mbeans hérités, et comment mixer différents modèles de
composants » pour obtenir des informations pour pouvoir déclarer et utiliser des MBeans hérités.
6.5. Mbeans hérités, et comment mixer différents modèles de
composants
La façon la plus simple de mixer différents modèles de composants est expliquée dans Exemple 6.7,
53
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
« Injecter un POJO dans un MBean ».
Exemple 6.7. Injecter un POJO dans un MBean
<server>
<mbean code="org.jboss.demos.models.mbeans.Pojo"
name="jboss.demos:service=pojo">
<attribute name="OtherPojo"><inject bean="PlainPojo"/></attribute>
</mbean>
</server>
Pour effectuer un déploiement MBeans via Microcontainer, vous devez rédiger un nouveau gestionnaire
pour le modèle du composant. Voir system -jm x-beans.xm l pour obtenir davantage d'informations. Le
code de ce fichier réside dans le code source du serveur de JBoss Application : le sous-projet systemjmx.
6.6. Exposer les POJO en tant que MBeans
Exemple 6.8. Exposer un POJO existant en tant que MBean
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="AnnotatedJMXPojo" class="org.jboss.demos.models.jmx.AtJmxPojo"/>
<bean name="XmlJMXPojo" class="org.jboss.demos.models.mbeans.Pojo">
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(exposedInterface=org.jb
oss.demos.models.mbeans.PojoMBean.class, registerDirectly=true)</annotation>
</bean>
<bean name="ExposedPojo" class="org.jboss.demos.models.jmx.Pojo"/>
<bean name="AnnotatedExposePojo"
class="org.jboss.demos.models.jmx.ExposePojo">
<constructor>
<parameter><inject bean="ExposedPojo"/></parameter>
</constructor>
</bean>
</deployment>
Ce descripteur expose un POJO existant en tant que MBean, et l'enregistre dans un serveur MBean.
Pour exposer un POJO en tant que MBean, terminez-le par l'annotation @JMX, en assumant que vous
ayez importé org.jboss.aop.m icrocontainer.aspects.jm x.JMX. Le bean peut alors être
exposé directement, ou bien dans sa propriété.
54
Chapitre 6. Modèles de composants
Exemple 6.9. Exposer un POJO en tant que MBean en utilisant sa propriété
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="XMLLoginConfig"
class="org.jboss.demos.models.old.XMLLoginConfig"/>
<bean name="SecurityConfig" class="org.jboss.demos.models.old.SecurityConfig">
<property name="defaultLoginConfig"><inject
bean="XMLLoginConfig"/></property>
</bean>
<bean name="SecurityChecker" class="org.jboss.demos.models.old.Checker">
<property name="loginConfig"><inject
bean="jboss.security:service=XMLLoginConfig"/></property>
<property name="securityConfig"><inject
bean="jboss.security:service=SecurityConfig"/></property>
</bean>
</deployment>
Vous pouvez utiliser n'importe quel type de recherche d'injection, soit en recherchant un POJO simple,
ou en obtenant un gestionnaire pour un MBean à partir du serveur MBean. Une des options d'injection
consiste à utiliser injection type, parfois nommée autowiring, comme vous verrez dans Exemple 6.10,
« Autowiring ».
Exemple 6.10. Autowiring
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="FromGuice" class="org.jboss.demos.models.plain.FromGuice">
<constructor><parameter><inject bean="PlainPojo"/></parameter></constructor>
<property name="guicePojo"><inject/></property>
</bean>
<bean name="AllPojos" class="org.jboss.demos.models.plain.AllPojos">
<property name="directMBean"><inject
bean="jboss.demos:service=pojo"/></property>
<property name="exposedMBean"><inject
bean="jboss.demos:service=ExposedPojo"/></property>
<property name="exposedMBean"><inject
bean="jboss.demos:service=ExposedPojo"/></property>
</bean>
</deployment>
Le bean FromGuice injecte le bean Guice par la correponsdance de type, avec PlainPojo injecté par
55
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
une injection de nom commun. Maintenant, vous pouvez tester la liaison Guice fonctionne comme prévu
dans Exemple 6.11, « T ester la fonctionnalité Guice ».
Exemple 6.11. T ester la fonctionnalité Guice
public class FromGuice {
private IPojo plainPojo;
private org.jboss.demos.models.guice.Pojo guicePojo;
public FromGuice(IPojo plainPojo)
{
this.plainPojo = plainPojo;
}
public void setGuicePojo(org.jboss.demos.models.guice.Pojo guicePojo)
{
this.guicePojo = guicePojo;
}
public void start()
{
f (plainPojo != guicePojo.getMcPojo())
throw new IllegalArgumentException("Pojos are not the same: " + plainPojo +
"!=" + guicePojo.getMcPojo());
}
}
Exemple 6.11, « T ester la fonctionnalité Guice » ne fournit qu'un modèle de composant alias. L'alias est
une fonctionnalité triviale, mais nécessaire. Il doit être présenté comme un nouveau modèle de
composant à l'intérieur du Microcontainer, pour pouvoir l'implémenter en tant que véritable dépendance.
Les détails d'implémentation sont disponibles dans Exemple 6.12, « Code source du
AbstractController ».
Exemple 6.12. Code source du AbstractController
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<alias name="SpringPojo">springPojo</alias>
</deployment>
Le descripteur mappe le nom SpringPojo à l'alias springPojo. L'avantage des alias en tant que véritables
modèles de composants, c'est que le timing de déploiement de beans devient moins important. L'alias
patiente dans un état non-installé jusqu'à ce qu'un véritable bean le déclenche.
56
Chapitre 7. Injection de dépendances avancées et IoC
Chapitre 7. Injection de dépendances avancées et IoC
Aujourd'hui, Dependency injection (DI), qui s'appelle également Inversion of Control (IoC), est au coeur
de nombreux frameworks qui embrassent la notion d'un modèle de composant ou de conteneur. Nous
avons abordé les modèles de composants dans un chapitre précédent. Le noyau JBoss JMX,
précurseur du Microcontainer, ne fournit qu'un support léger DI/IoC, surtout en raison des limitations
pour accéder à MBeans par le serveur MBeans. Cependant, avec le nouveau modèle de composant
basé-POJO, on trouve plusieurs fonctionnalités à la fois nouvelles et intéressantes.
Ce chapitre vous montre comment appliquer différents concepts DI à l'aide du Microcontainer JBoss.
Ces concepts seront exprimés par le code XML, mais vous pourrez appliquer la plupart de ces
fonctionnalités en utilisant des annotations.
7.1. Usine de valeurs
Une usine de valeurs est un bean qui possède une ou plusieurs méthodes destinées à générer des
valeurs. Voir Exemple 7.1, « Usine de valeurs ».
57
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 7.1. Usine de valeurs
<bean name="Binding" class="org.jboss.demos.ioc.vf.PortBindingManager">
<constructor>
<parameter>
<map keyClass="java.lang.String" valueClass="java.lang.Integer">
<entry>
<key>http</key>
<value>80</value>
</entry>
<entry>
<key>ssh</key>
<value>22</value>
</entry>
</map>
</parameter>
</constructor>
</bean>
<bean name="PortsConfig" class="org.jboss.demos.ioc.vf.PortsConfig">
<property name="http"><value-factory bean="Binding" method="getPort"
parameter="http"/></property>
<property name="ssh"><value-factory bean="Binding" method="getPort"
parameter="ssh"/></property>
<property name="ftp">
<value-factory bean="Binding" method="getPort">
<parameter>ftp</parameter>
<parameter>21</parameter>
</value-factory>
</property>
<property name="mail">
<value-factory bean="Binding" method="getPort">
<parameter>mail</parameter>
<parameter>25</parameter>
</value-factory>
</property>
</bean>
Exemple 7.2, « PortsConfig » montre comment le bean PortsConfig utilise le bean de Liaison pour obtenir
ses valeurs par l'invocation de méthode getPort.
58
Chapitre 7. Injection de dépendances avancées et IoC
Exemple 7.2. PortsConfig
public class PortBindingManager {
private Map<String, Integer> bindings;
public PortBindingManager(Map<String, Integer> bindings)
{
this.bindings = bindings;
}
public Integer getPort(String key)
{
return getPort(key, null);
}
public Integer getPort(String key, Integer defaultValue)
{
if (bindings == null)
return defaultValue;
Integer value = bindings.get(key);
if (value != null)
return value;
if (defaultValue != null)
bindings.put(key, defaultValue);
return defaultValue;
}
}
7.2. Callbacks
Le descripteur qui s'affiche dans Exemple 7.3, « Callbacks à collecter et beans de filtrage » vous permet
de collecter tous les beans d'un certain type, et même de limiter le nombre de beans correspondants.
En conjonction au descripteur Exemple 7.3, « Callbacks à collecter et beans de filtrage », le code Java
affiché dans Exemple 7.4, « Un analyseur pour collecter tous les éditeurs » montre un Parser
(analyseur ou lecteur) qui collecte tous les Editor (éditeur)
59
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 7.3. Callbacks à collecter et beans de filtrage
<bean name="checker" class="org.jboss.demos.ioc.callback.Checker">
<constructor>
<parameter>
<value-factory bean="parser" method="parse">
<parameter>
<array elementClass="java.lang.Object">
<value>http://www.jboss.org</value>
<value>SI</value>
<value>3.14</value>
<value>42</value>
</array>
</parameter>
</value-factory>
</parameter>
</constructor>
</bean>
<bean name="editorA" class="org.jboss.demos.ioc.callback.DoubleEditor"/>
<bean name="editorB" class="org.jboss.demos.ioc.callback.LocaleEditor"/>
<bean name="parser" class="org.jboss.demos.ioc.callback.Parser">
<incallback method="addEditor" cardinality="4..n"/>
<uncallback method="removeEditor"/>
</bean>
<bean name="editorC" class="org.jboss.demos.ioc.callback.LongEditor"/>
<bean name="editorD" class="org.jboss.demos.ioc.callback.URLEditor"/>
Exemple 7.4 . Un analyseur pour collecter tous les éditeurs
public class Parser {
private Set<Editor> editors = new HashSet<Editor>();
...
public void addEditor(Editor editor)
{
editors.add(editor);
}
public void removeEditor(Editor editor)
{
editors.remove(editor);
}
}
Notez que incallback et uncallback utilisent le nom de la méthode pour la correspondance.
60
Chapitre 7. Injection de dépendances avancées et IoC
<incallback method="addEditor" cardinality="4..n"/>
<uncallback method="removeEditor"/>
Une limite contrôle le nombre d'éditeurs qui peuvent entraîner le bean à progresser vers un état
Configuré : cardinality=4 ..n/>
Finalement, Checker est créé et contrôle l'analyseur. Cela est illustré dans Exemple 7.5, « Checker
d'analyseur. ».
Exemple 7.5. Checker d'analyseur.
public void create() throws Throwable {
Set<String> strings = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
for (Object element : elements)
strings.add(element.toString());
if (expected.equals(strings) == false)
throw new IllegalArgumentException("Illegal expected set: " + expected + "!=" +
strings);
}
7.3. Mode d'accès de bean
Avec BeanAccessMode par défaut, les champ d'un bean ne sont pas inspectés. Cependant, si cous
précisez un nouveau BeanAccessMode, les champs seront accessibles puisqu'ils font partie des
propriétés du bean. Voir Exemple 7.6, « Définitions possibles de BeanAccessMode », Exemple 7.7,
« Configurer le BeanAccessMode », et Exemple 7.8, « La classe FieldsBean » pour une
implémentation.
Exemple 7.6. Définitions possibles de BeanAccessMode
public enum BeanAccessMode {
STANDARD(BeanInfoCreator.STANDARD), // Getters and Setters
FIELDS(BeanInfoCreator.FIELDS), // Getters/Setters and fields without getters
and setters
ALL(BeanInfoCreator.ALL); // As above but with non public fields included
}
Ici, une valeur de String est allouée à un champ de String privé.
61
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 7.7. Configurer le BeanAccessMode
<bean name="FieldsBean" class="org.jboss.demos.ioc.access.FieldsBean" accessmode="ALL">
<property name="string">InternalString</property>
</bean>
Exemple 7.8. La classe FieldsBean
public class FieldsBean {
private String string;
public void start()
{
if (string == null)
throw new IllegalArgumentException("Strings should be set!");
}
}
7.4. Bean Alias
Chaque bean peut contenir un certain nombre d'alias. Comme les noms de composants de
Microcontainer sont traités comme des objets, le type d'alias n'est pas limité. Le remplacement d'une
propriété de système n'existe pas par défaut, vous devez poser le drapeau de remplacement
explicitement, comme le montre Exemple 7.9, « Un simple alias de bean ».
Exemple 7.9. Un simple alias de bean
<bean name="SimpleName" class="java.lang.Object">
<alias>SimpleAlias</alias>
<alias replace="true">${some.system.property}</alias>
<alias class="java.lang.Integer">12345</alias>
<alias><javabean xmlns="urn:jboss:javabean:2.0"
class="org.jboss.demos.bootstrap.Main"/></alias>
</bean>
7.5. Support d'annotations XML (ou Métadonnées)
Le support AOP est une fonctionnalité principale de JBoss Microcontainer. Vous pouvez utiliser les
62
Chapitre 7. Injection de dépendances avancées et IoC
aspects AOP ou les simples beans dans n'importe quelle combinaison. Exemple 7.10, « Intercepter une
méthode basée Annotation » tente d'intercepter une invocation de méthode sur la base d'une
annotation. L'annotation peut provenir de n'importe quel endroit. Il peut s'agir d'une annotation de classe
ou d'une annotation ajoutée à travers la configuration xml.
Exemple 7.10. Intercepter une méthode basée Annotation
<interceptor xmlns="urn:jboss:aop-beans:1.0" name="StopWatchInterceptor"
class="org.jboss.demos.ioc.annotations.StopWatchInterceptor"/>
<bind xmlns="urn:jboss:aop-beans:1.0" pointcut="execution(*
@org.jboss.demos.ioc.annotations.StopWatchLog->*(..)) OR execution(* *>@org.jboss.demos.ioc.annotations.StopWatchLog(..))">
<interceptor-ref name="StopWatchInterceptor"/>
</bind>
</interceptor>
public class StopWatchInterceptor implements Interceptor {
...
public Object invoke(Invocation invocation) throws Throwable
{
Object target = invocation.getTargetObject();
long time = System.currentTimeMillis();
log.info("Invocation [" + target + "] start: " + time);
try
{
return invocation.invokeNext();
}
finally
{
log.info("Invocation [" + target + "] time: " + (System.currentTimeMillis() time));
}
}
}
Exemple 7.11, « Un exécuteur annoté true class » and Exemple 7.12, « Simple exécuteur avec
annotation XML » montre différentes façons d'implémenter les exécuteurs.
63
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 7.11. Un exécuteur annoté true class
<bean name="AnnotatedExecutor"
class="org.jboss.demos.ioc.annotations.AnnotatedExecutor">
public class AnnotatedExecutor implements Executor {
...
@StopWatchLog // <-- Pointcut match!
public void execute() throws Exception {
delegate.execute();
}
}
Exemple 7.12. Simple exécuteur avec annotation XML
<bean name="SimpleExecutor"
class="org.jboss.demos.ioc.annotations.SimpleExecutor">
<annotation>@org.jboss.demos.ioc.annotations.StopWatchLog</annotation> // <-Pointcut match!
</bean>
public class SimpleExecutor implements Executor {
private static Random random = new Random();
public void execute() throws Exception
{
Thread.sleep(Math.abs(random.nextLong() % 101));
}
}
Après avoir ajouté des beans invocateurs exécuteurs, vous pourrez voir les exécuteurs en action
pendant l'emploi, en regardant dans les sorties de log telles que Exemple 7.13, « Sortie de Log
d'Executeur ».
64
Chapitre 7. Injection de dépendances avancées et IoC
Exemple 7.13. Sortie de Log d'Executeur
JBoss-MC-Demo INFO [15-12-2008 13:57:39] StopWatch - Invocation
[org.jboss.demos.ioc.annotations.AnnotatedExecutor@4d28c7] start: 1229345859234
JBoss-MC-Demo INFO [15-12-2008 13:57:39] StopWatch - Invocation
[org.jboss.demos.ioc.annotations.AnnotatedExecutor@4d28c7] time: 31
JBoss-MC-Demo INFO [15-12-2008 13:57:39] StopWatch - Invocation
[org.jboss.demos.ioc.annotations.SimpleExecutor@1b044df] start: 1229345859265
JBoss-MC-Demo INFO [15-12-2008 13:57:39] StopWatch - Invocation
[org.jboss.demos.ioc.annotations.SimpleExecutor@1b044df] time: 47
7.6. Autowire
Autowiring ou injection contextuelle, est une fonctionnalité commune des frameworks IoC. Exemple 7.14,
« Inclure ou exclure avec Autowiring » vous montre comment utiliser ou exclure des beans d'autowiring.
Exemple 7.14 . Inclure ou exclure avec Autowiring
<bean name="Square" class="org.jboss.demos.ioc.autowire.Square" autowirecandidate="false"/>
<bean name="Circle" class="org.jboss.demos.ioc.autowire.Circle"/>
<bean name="ShapeUser" class="org.jboss.demos.ioc.autowire.ShapeUser">
<constructor>
<parameter><inject/></parameter>
</constructor>
</bean>
<bean name="ShapeHolder" class="org.jboss.demos.ioc.autowire.ShapeHolder">
<incallback method="addShape"/>
<uncallback method="removeShape"/>
</bean>
<bean name="ShapeChecker" class="org.jboss.demos.ioc.autowire.ShapesChecker"/>
Dans les deux cas - ShapeUser et ShapeChecker - seul Circle doit être utilisé, car Square est exclus du
contexte de liaison.
7.7. Usine de bean
Quand vous souhaitez plus d'une instance pour un bean particulier, vous devez utiliser le modèle
d'usine de bean. Le travail du Microcontainer consiste à configurer ou à installer l'usine de beans,
comme s,il s'agissait d'un bean simple. ensuite, vous aurez besoin d'invoquer la méthode createBean
de l'usine de beans.
Par défaut, le Microcontainer crée une instance GenericBeanFactory , mais vous pouvez configurer
votre propre usine. La seule limitation est que sa signature et des crochets de configuration
ressemblent à ceux de AbstractBeanFactory.
65
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 7.15. Usine de beans génériques
<bean name="Object" class="java.lang.Object"/>
<beanfactory name="DefaultPrototype"
class="org.jboss.demos.ioc.factory.Prototype">
<property name="value"><inject bean="Object"/></property>
</beanfactory>
<beanfactory name="EnhancedPrototype"
class="org.jboss.demos.ioc.factory.Prototype"
factoryClass="org.jboss.demos.ioc.factory.EnhancedBeanFactory">
<property name="value"><inject bean="Object"/></property>
</beanfactory>
<beanfactory name="ProxiedPrototype"
class="org.jboss.demos.ioc.factory.UnmodifiablePrototype"
factoryClass="org.jboss.demos.ioc.factory.EnhancedBeanFactory">
<property name="value"><inject bean="Object"/></property>
</beanfactory>
<bean name="PrototypeCreator"
class="org.jboss.demos.ioc.factory.PrototypeCreator">
<property name="default"><inject bean="DefaultPrototype"/></property>
<property name="enhanced"><inject bean="EnhancedPrototype"/></property>
<property name="proxied"><inject bean="ProxiedPrototype"/></property>
</bean>
Voir Exemple 7.16, « BeanFactory étendue » pour l'utilisation d'une BeanFactory étendue.
66
Chapitre 7. Injection de dépendances avancées et IoC
Exemple 7.16. BeanFactory étendue
public class EnhancedBeanFactory extends GenericBeanFactory {
public EnhancedBeanFactory(KernelConfigurator configurator)
{
super(configurator);
}
public Object createBean() throws Throwable
{
Object bean = super.createBean();
Class clazz = bean.getClass();
if (clazz.isAnnotationPresent(SetterProxy.class))
{
Set<Class> interfaces = new HashSet<Class>();
addInterfaces(clazz, interfaces);
return Proxy.newProxyInstance(
clazz.getClassLoader(),
interfaces.toArray(new Class[interfaces.size()]),
new SetterInterceptor(bean)
);
}
else
{
return bean;
}
}
protected static void addInterfaces(Class clazz, Set<Class> interfaces)
{
if (clazz == null)
return;
interfaces.addAll(Arrays.asList(clazz.getInterfaces()));
addInterfaces(clazz.getSuperclass(), interfaces);
}
private class SetterInterceptor implements InvocationHandler
{
private Object target;
private SetterInterceptor(Object target)
{
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable
{
String methodName = method.getName();
if (methodName.startsWith("set"))
throw new IllegalArgumentException("Cannot invoke setters.");
return method.invoke(target, args);
}
}
}
67
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
public class PrototypeCreator {
...
public void create() throws Throwable
{
ValueInvoker vi1 = (ValueInvoker)bfDefault.createBean();
vi1.setValue("default");
ValueInvoker vi2 = (ValueInvoker)enhanced.createBean();
vi2.setValue("enhanced");
ValueInvoker vi3 = (ValueInvoker)proxied.createBean();
try
{
vi3.setValue("default");
throw new Error("Should not be here.");
}
catch (Exception ignored)
{
}
}
7.8. Constructeur de métadonnées de beans
Quand vous utilisez le Microcontainer dans votre code, utiliser BeanMetaDataBuilder pour créer et
configurer les métadonnées de votre bean.
68
Chapitre 7. Injection de dépendances avancées et IoC
Exemple 7.17. BeanMetaDataBuilder
<bean name="BuilderUtil" class="org.jboss.demos.ioc.builder.BuilderUtil"/>
<bean name="BuilderExampleHolder"
class="org.jboss.demos.ioc.builder.BuilderExampleHolder">
<constructor>
<parameter><inject bean="BUExample"/></parameter>
</constructor>
</bean>
En utilisant ce concept, vous n'exposez pas votre code à des détails d'implémentation de
Microcontainer.
public class BuilderUtil {
private KernelController controller;
@Constructor
public BuilderUtil(@Inject(bean = KernelConstants.KERNEL_CONTROLLER_NAME)
KernelController controller) {
this.controller = controller;
}
public void create() throws Throwable {
BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder("BUExample",
BuilderExample.class.getName());
builder.addStartParameter(Kernel.class.getName(),
builder.createInject(KernelConstants.KERNEL_NAME));
controller.install(builder.getBeanMetaData());
}
public void destroy() {
controller.uninstall("BUExample");
}
}
7.9. Personnalisation du chargeur de classes.
Dans le Microcontainer, vous pouvez définir un chargeur de classes par bean. Quand vous définissez
un chargeur de classes pour tout le déploiement, faîtes attention de ne pas créer une dépendance
cyclique -- par exemple, un chargeur de classes qui dépendrait de lui-même.
69
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 7.18. Définir un chargeur de classe par bean
<classloader><inject bean="custom-classloader:0.0.0"/></classloader>
<!-- this will be explained in future article -->
<classloader name="custom-classloader" xmlns="urn:jboss:classloader:1.0" exportall="NON_EMPTY" import-all="true"/>
<bean name="CustomCL" class="org.jboss.demos.ioc.classloader.CustomClassLoader">
<constructor>
<parameter><inject bean="custom-classloader:0.0.0"/></parameter>
</constructor>
<property name="pattern">org\.jboss\.demos\.ioc\..+</property>
</bean>
<bean name="CB1" class="org.jboss.demos.ioc.classloader.CustomBean"/>
<bean name="CB2" class="org.jboss.demos.ioc.classloader.CustomBean">
<classloader><inject bean="CustomCL"/></classloader>
</bean>
Exemple 7.19, « Personnalisation du test de chargeur de classe » montre un test qui vérifie que le bean
CB2 utilise un chargeur de classes personnalisé. qui limite l'étendue des packages chargeables.
Exemple 7.19. Personnalisation du test de chargeur de classe
public class CustomClassLoader extends ClassLoader {
private Pattern pattern;
public CustomClassLoader(ClassLoader parent) {
super(parent);
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (pattern == null || pattern.matcher(name).matches())
return super.loadClass(name);
else
throw new ClassNotFoundException("Name '" + name + "' doesn't match pattern:
" + pattern);
}
public void setPattern(String regexp) {
pattern = Pattern.compile(regexp);
}
}
7.10. Mode Controller
Par défaut, le Microcontainer utilise le mode contrôleur AUT O. Il pousse les beans autant que possible,
en fonction des dépendances. Il existe, cependant, deux autres modes : MANUAL et ON_DEMAND.
Si le bean est marqué ON_DEMAND, il ne sera pas utilisé ou installé à moins qu'un autre bean en
70
Chapitre 7. Injection de dépendances avancées et IoC
dépende explicitement. En mode MANUAL, l'utilsateur du Microcontainer doit pousser le bean en avant et
en arrière le long de l'échelle des états.
Exemple 7.20. Bean Controller Mode
<bean name="OptionalService" class="org.jboss.demos.ioc.mode.OptionalService"
mode="On Demand"/>
<bean name="OptionalServiceUser"
class="org.jboss.demos.ioc.mode.OptionalServiceUser"/>
<bean name="ManualService" class="org.jboss.demos.ioc.mode.ManualService"
mode="Manual"/>
<bean name="ManualServiceUser"
class="org.jboss.demos.ioc.mode.ManualServiceUser">
<start>
<parameter><inject bean="ManualService" fromContext="context" state="Not
Installed"/></parameter>
</start>
</bean>
Note
En utilisant l'attribut fromContext de la classe inject, vous pouvez injecter des beans, ainsi que
leur représentation de composant de Microcontainer non modifiable.
Réviser le code de OptionalServiceUser et de ManualServiceUser sur la façon d'utiliser l'API
Microcontainer pour la gestion de bean ON_DEMAND ou MANUAL.
7.11. Cycle
Dans un cycle, les beans dépendent parfois les uns des autres. Ainsi, A dépend de B au moment de la
constrution, mais B dépend de A pour la méthode setter. Le problème peut être résolu grâce à la
séparation du cycle de vie d'état à fine granularité du Microcontainer.
71
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 7.21. Séparation du cycle de vie de bean
<bean name="cycleA" class="org.jboss.demos.ioc.cycle.CyclePojo">
<property name="dependency"><inject bean="cycleB"/></property>
</bean>
<bean name="cycleB" class="org.jboss.demos.ioc.cycle.CyclePojo">
<constructor><parameter><inject bean="cycleA"
state="Instantiated"/></parameter></constructor>
</bean>
<bean name="cycleC" class="org.jboss.demos.ioc.cycle.CyclePojo">
<property name="dependency"><inject bean="cycleD"/></property>
</bean>
<bean name="cycleD" class="org.jboss.demos.ioc.cycle.CyclePojo">
<property name="dependency"><inject bean="cycleC"
state="Instantiated"/></property>
</bean>
7.12. Offre et demande
Parfois, comme pour le cas d'une injection, la dépendance entre deux beans n'est peut-être pas
apparente. De telles dépendances doivent être présentées clairement, comme le montre Exemple 7.22,
« Utilisation d'un code statique ».
Exemple 7.22. Utilisation d'un code statique
<bean name="TMDemand" class="org.jboss.demos.ioc.demandsupply.TMDemander">
<demand>TM</demand>
</bean>
<bean name="SimpleTMSupply"
class="org.jboss.demos.ioc.demandsupply.SimpleTMSupplyer">
<supply>TM</supply>
</bean>
7.13. Installs
Au fur et à mesure que les beans évoluent vers des états différents, vous souhaiterez sans doute
invoquer certaines méthodes vers d'autres beans ou sur le même bean. Exemple 7.23, « Méthodes
d'invocation dans des états différents » vous montre comment Entry invoque les méthodes add et
rem oveEntryRepositoryManager pour s'enregistrer et se désenregistrer.
72
Chapitre 7. Injection de dépendances avancées et IoC
Exemple 7.23. Méthodes d'invocation dans des états différents
<bean name="RepositoryManager"
class="org.jboss.demos.ioc.install.RepositoryManager">
<install method="addEntry">
<parameter><inject fromContext="name"/></parameter>
<parameter><this/></parameter>
</install>
<uninstall method="removeEntry">
<parameter><inject fromContext="name"/></parameter>
</uninstall>
</bean>
<bean name="Entry" class="org.jboss.demos.ioc.install.SimpleEntry">
<install bean="RepositoryManager" method="addEntry" state="Instantiated">
<parameter><inject fromContext="name"/></parameter>
<parameter><this/></parameter>
</install>
<uninstall bean="RepositoryManager" method="removeEntry" state="Configured">
<parameter><inject fromContext="name"/></parameter>
</uninstall>
</bean>
7.14. Lazy Mock
Vous avez peut-être une dépendance de bean que vous n'utilisez que très rarement, mais qui prend
longtemps à configurer. Vous pouvez utiliser un Lazy Mock du bean, comme expliqué dans
Exemple 7.24, « Lazy Mock », pour résoudre la dépendance. Quand vous avez besoin d'un bean,
invoquez et utilisez le bean cible, en espérant qu'il a maintenant été installé.
73
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 7.24 . Lazy Mock
<bean name="lazyA" class="org.jboss.demos.ioc.lazy.LazyImpl">
<constructor>
<parameter>
<lazy bean="lazyB">
<interface>org.jboss.demos.ioc.lazy.ILazyPojo</interface>
</lazy>
</parameter>
</constructor>
</bean>
<bean name="lazyB" class="org.jboss.demos.ioc.lazy.LazyImpl">
<constructor>
<parameter>
<lazy bean="lazyA">
<interface>org.jboss.demos.ioc.lazy.ILazyPojo</interface>
</lazy>
</parameter>
</constructor>
</bean>
<lazy name="anotherLazy" bean="Pojo" exposeClass="true"/>
<bean name="Pojo" class="org.jboss.demos.ioc.lazy.Pojo"/>
7.15. Cycle de vie
Le micro-conteneur utilise par défaut les méthodes create, start, et destroy quand il évolue entre
les différents états. Vous ne souhaitez sans doute pas que le Microcontainer les invoque. Pour cette
raison, un drapeau ignore est disponible.
Exemple 7.25. Cycles de vie de beans
<bean name="FullLifecycleBean-3"
class="org.jboss.demos.ioc.lifecycle.FullLifecycleBean"/>
<bean name="FullLifecycleBean-2"
class="org.jboss.demos.ioc.lifecycle.FullLifecycleBean">
<create ignored="true"/>
</bean>
<bean name="FullLifecycleBean-1"
class="org.jboss.demos.ioc.lifecycle.FullLifecycleBean">
<start ignored="true"/>
</bean>
74
Chapitre 8. The Virtual File System
Chapitre 8. The Virtual File System
Duplication of resource-handling code is a common problem for developers. In most cases, the code
deals with determining information about a particular resource, which might be a file, a directory, or, in the
case of a JAR, a remote URL. Another duplication problem is code for the processing of nested archives.
Exemple 8.1, « Resource Duplication Problem » illustrates the problem.
75
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 8.1. Resource Duplication Problem
76
Chapitre 8. The Virtual File System
public static URL[] search(ClassLoader cl, String prefix, String suffix) throws
IOException {
Enumeration[] e = new Enumeration[]{
cl.getResources(prefix),
cl.getResources(prefix + "MANIFEST.MF")
};
Set all = new LinkedHashSet();
URL url;
URLConnection conn;
JarFile jarFile;
for (int i = 0, s = e.length; i < s; ++i)
{
while (e[i].hasMoreElements())
{
url = (URL)e[i].nextElement();
conn = url.openConnection();
conn.setUseCaches(false);
conn.setDefaultUseCaches(false);
if (conn instanceof JarURLConnection)
{
jarFile = ((JarURLConnection)conn).getJarFile();
}
else
{
jarFile = getAlternativeJarFile(url);
}
if (jarFile != null)
{
searchJar(cl, all, jarFile, prefix, suffix);
}
else
{
boolean searchDone = searchDir(all, new
File(URLDecoder.decode(url.getFile(), "UTF-8")), suffix);
if (searchDone == false)
{
searchFromURL(all, prefix, suffix, url);
}
}
}
}
return (URL[])all.toArray(new URL[all.size()]);
}
private static boolean searchDir(Set result, File file, String suffix) throws
IOException
{
if (file.exists() && file.isDirectory())
{
File[] fc = file.listFiles();
String path;
for (int i = 0; i < fc.length; i++)
{
path = fc[i].getAbsolutePath();
if (fc[i].isDirectory())
{
searchDir(result, fc[i], suffix);
}
else if (path.endsWith(suffix))
{
77
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
result.add(fc[i].toURL());
}
}
return true;
}
return false;
}
T here are also many problems with file locking on Windows systems, forcing developers to copy all hotdeployable archives to another location to prevent locking those in deploy folders (which would prevent
their deletion and file-system based undeploy). File locking is a major problem whose only solution used
to be centralizing all the resource loading code in one place.
T he VFS project was created solve all of these issues. VFS stands for Virtual File System.
8.1. VFS Public API
VFS is used for two main purposes, as shown in Uses for VFS.
Uses for VFS
simple resource navigation
visitor pattern API (Application Programmer Interface)
As mentioned, in plain JDK, handling and navigating resources are complex. You must always check the
resource type, and these checks can be cumbersome. VFS abstracts resources into a single resource
type, VirtualFile.
78
Chapitre 8. The Virtual File System
Exemple 8.2. T he VirtualFile Resource T ype
79
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
public class VirtualFile implements Serializable {
/**
* Get certificates.
*
* @return the certificates associated with this virtual file
*/
Certificate[] getCertificates()
/**
* Get the simple VF name (X.java)
*
* @return the simple file name
* @throws IllegalStateException if the file is closed
*/
String getName()
/**
* Get the VFS relative path name (org/jboss/X.java)
*
* @return the VFS relative path name
* @throws IllegalStateException if the file is closed
*/
String getPathName()
/**
* Get the VF URL (file://root/org/jboss/X.java)
*
* @return the full URL to the VF in the VFS.
* @throws MalformedURLException if a url cannot be parsed
* @throws URISyntaxException if a uri cannot be parsed
* @throws IllegalStateException if the file is closed
*/
URL toURL() throws MalformedURLException, URISyntaxException
/**
* Get the VF URI (file://root/org/jboss/X.java)
*
* @return the full URI to the VF in the VFS.
* @throws URISyntaxException if a uri cannot be parsed
* @throws IllegalStateException if the file is closed
* @throws MalformedURLException for a bad url
*/
URI toURI() throws MalformedURLException, URISyntaxException
/**
* When the file was last modified
*
* @return the last modified time
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalStateException if the file is closed
*/
long getLastModified() throws IOException
/**
* Returns true if the file has been modified since this method was last
called
* Last modified time is initialized at handler instantiation.
*
* @return true if modifed, false otherwise
* @throws IOException for any error
80
Chapitre 8. The Virtual File System
*/
boolean hasBeenModified() throws IOException
/**
* Get the size
*
* @return the size
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalStateException if the file is closed
*/
long getSize() throws IOException
/**
* Tests whether the underlying implementation file still exists.
* @return true if the file exists, false otherwise.
* @throws IOException - thrown on failure to detect existence.
*/
boolean exists() throws IOException
/**
* Whether it is a simple leaf of the VFS,
* i.e. whether it can contain other files
*
* @return true if a simple file.
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalStateException if the file is closed
*/
boolean isLeaf() throws IOException
/**
* Is the file archive.
*
* @return true if archive, false otherwise
* @throws IOException for any error
*/
boolean isArchive() throws IOException
/**
* Whether it is hidden
*
* @return true when hidden
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalStateException if the file is closed
*/
boolean isHidden() throws IOException
/**
* Access the file contents.
*
* @return an InputStream for the file contents.
* @throws IOException for any error accessing the file system
* @throws IllegalStateException if the file is closed
*/
InputStream openStream() throws IOException
/**
* Do file cleanup.
*
* e.g. delete temp files
*/
81
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
void cleanup()
/**
* Close the file resources (stream, etc.)
*/
void close()
/**
* Delete this virtual file
*
* @return true if file was deleted
* @throws IOException if an error occurs
*/
boolean delete() throws IOException
/**
* Delete this virtual file
*
* @param gracePeriod max time to wait for any locks (in milliseconds)
* @return true if file was deleted
* @throws IOException if an error occurs
*/
boolean delete(int gracePeriod) throws IOException
/**
* Get the VFS instance for this virtual file
*
* @return the VFS
* @throws IllegalStateException if the file is closed
*/
VFS getVFS()
/**
* Get the parent
*
* @return the parent or null if there is no parent
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalStateException if the file is closed
*/
VirtualFile getParent() throws IOException
/**
* Get a child
*
* @param path the path
* @return the child or <code>null</code> if not found
* @throws IOException for any problem accessing the VFS
* @throws IllegalArgumentException if the path is null
* @throws IllegalStateException if the file is closed or it is a leaf node
*/
VirtualFile getChild(String path) throws IOException
/**
* Get the children
*
* @return the children
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalStateException if the file is closed
*/
List<VirtualFile> getChildren() throws IOException
82
Chapitre 8. The Virtual File System
/**
* Get the children
*
* @param filter to filter the children
* @return the children
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalStateException if the file is closed or it is a leaf node
*/
List<VirtualFile> getChildren(VirtualFileFilter filter) throws IOException
/**
* Get all the children recursively<p>
*
* This always uses {@link VisitorAttributes#RECURSE}
*
* @return the children
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalStateException if the file is closed
*/
List<VirtualFile> getChildrenRecursively() throws IOException
/**
* Get all the children recursively<p>
*
* This always uses {@link VisitorAttributes#RECURSE}
*
* @param filter to filter the children
* @return the children
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalStateException if the file is closed or it is a leaf node
*/
List<VirtualFile> getChildrenRecursively(VirtualFileFilter filter) throws
IOException
/**
* Visit the virtual file system
*
* @param visitor the visitor
* @throws IOException for any problem accessing the virtual file system
* @throws IllegalArgumentException if the visitor is null
* @throws IllegalStateException if the file is closed
*/
void visit(VirtualFileVisitor visitor) throws IOException
}
All of the usual read-only File System operations are available, plus a few options to cleanup or delete
the resource. Cleanup or deletion handling is needed when dealing with some internal temporary files,
such as files created to handle nested jars.
T o switch from the JDK's File or URL resource handling to new VirtualFile you need a root VirtualFile,
which is provided by the VFS class, with the help of URL or URI parameter.
83
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 8.3. Using the VFS Class
84
Chapitre 8. The Virtual File System
public class VFS {
/**
* Get the virtual file system for a root uri
*
* @param rootURI the root URI
* @return the virtual file system
* @throws IOException if there is a problem accessing the VFS
* @throws IllegalArgumentException if the rootURL is null
*/
static VFS getVFS(URI rootURI) throws IOException
/**
* Create new root
*
* @param rootURI the root url
* @return the virtual file
* @throws IOException if there is a problem accessing the VFS
* @throws IllegalArgumentException if the rootURL
*/
static VirtualFile createNewRoot(URI rootURI) throws IOException
/**
* Get the root virtual file
*
* @param rootURI the root uri
* @return the virtual file
* @throws IOException if there is a problem accessing the VFS
* @throws IllegalArgumentException if the rootURL is null
*/
static VirtualFile getRoot(URI rootURI) throws IOException
/**
* Get the virtual file system for a root url
*
* @param rootURL the root url
* @return the virtual file system
* @throws IOException if there is a problem accessing the VFS
* @throws IllegalArgumentException if the rootURL is null
*/
static VFS getVFS(URL rootURL) throws IOException
/**
* Create new root
*
* @param rootURL the root url
* @return the virtual file
* @throws IOException if there is a problem accessing the VFS
* @throws IllegalArgumentException if the rootURL
*/
static VirtualFile createNewRoot(URL rootURL) throws IOException
/**
* Get the root virtual file
*
* @param rootURL the root url
* @return the virtual file
* @throws IOException if there is a problem accessing the VFS
* @throws IllegalArgumentException if the rootURL
*/
static VirtualFile getRoot(URL rootURL) throws IOException
85
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
/**
* Get the root file of this VFS
*
* @return the root
* @throws IOException for any problem accessing the VFS
*/
VirtualFile getRoot() throws IOException
}
T he three different methods look similar.
getVFS
createNewRoot
getRoot
getVFS returns a VFS instance but does not yet create a VirtualFile instance. T his is important because
there are methods which help with configuring a VFS instance (see VFS class API javadocs), before
instructing it to create a VirtualFile root.
T he other two methods, on the other hand, use default settings for root creation. T he difference between
createNewRoot and getRoot is in caching details, which are covered later.
Exemple 8.4 . Using getVFS
URL rootURL = ...; // get root url
VFS vfs = VFS.getVFS(rootURL);
// configure vfs instance
VirtualFile root1 = vfs.getRoot();
// or you can get root directly
VirtualFile root2 = VFS.crateNewRoot(rootURL);
VirtualFile root3 = VFS.getRoot(rootURL);
Another useful thing about VFS API is its implementation of a proper visitor pattern. It is very simple to
recursively gather different resources, a task which is difficult to do with plain JDK resource loading.
86
Chapitre 8. The Virtual File System
Exemple 8.5. Recursively Gathering Resources
public interface VirtualFileVisitor {
/**
* Get the search attribues for this visitor
*
* @return the attributes
*/
VisitorAttributes getAttributes();
/**
* Visit a virtual file
*
* @param virtualFile the virtual file being visited
*/
void visit(VirtualFile virtualFile);
}
VirtualFile root = ...; // get root
VirtualFileVisitor visitor = new SuffixVisitor(".class"); // get all classes
root.visit(visitor);
8.2. VFS Architecture
While the public API is quite intuitive, real implementation details add complexity. Some concepts need to
be explained in more detail.
Each time you create a VFS instance, its matching VFSContext instance is created. T his creation is
done via VFSContextFactory. Different protocols map to different VFSContextFactory instances.
For example, file/vfsfile maps to FileSystem ContextFactory, while zip/vfszip maps to
ZipEntryContextFactory.
Each time a VirtualFile instance is created, its matching VirtualFileHandler is created. T his
VirtualFileHandler instance knows how to handle different resource types properly; the VirtualFile
API only delegates invocations to its VirtualFileHandler reference.
T he VFSContext instance knows how to create VirtualFileHandler instances accordingly to a resource
type. For example, Z ipEntryContextFactory creates ZipEntryContext, which then creates
ZipEntryHandler.
8.3. Existing Implementations
Apart from files, directories (FileHandler) and zip archives (Z ipEntryHandler) the Microcontainer also
supports other more advanced use cases. T he first one is Assembled, which is similar to what Eclipse
calls Linked Resources. Its purpose is to take existing resources from different trees, and "mock" them
into single resource tree.
87
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 8.6. Implementation of Assembled VirtualFileHandlers
AssembledDirectory sar =
AssembledContextFactory.getInstance().create("assembled.sar");
URL url = getResource("/vfs/test/jar1.jar");
VirtualFile jar1 = VFS.getRoot(url);
sar.addChild(jar1);
url = getResource("/tmp/app/ext.jar");
VirtualFile ext1 = VFS.getRoot(url);
sar.addChild(ext);
AssembledDirectory metainf = sar.mkdir("META-INF");
url = getResource("/config/jboss-service.xml");
VirtualFile serviceVF = VFS.getRoot(url);
metainf.addChild(serviceVF);
AssembledDirectory app = sar.mkdir("app.jar");
url = getResource("/app/someapp/classes");
VirtualFile appVF = VFS.getRoot(url);
app.addPath(appVF, new SuffixFilter(".class"));
Another implementation is in-memory files. T his implementation arose out of a need to easily handle
AOP generated bytes. Instead of using temporary files, you can drop bytes into in-memory
VirtualFileHandlers.
Exemple 8.7. Implementation of In-Memory VirtualFileHandlers
URL url = new URL("vfsmemory://aopdomain/org/acme/test/Test.class");
byte[] bytes = ...; // some AOP generated class bytes
MemoryFileFactory.putFile(url, bytes);
VirtualFile classFile = VFS.getVirtualFile(new URL("vfsmemory://aopdomain"),
"org/acme/test/Test.class");
InputStream bis = classFile.openStream(); // e.g. load class from input stream
8.4. Extension Hooks
It is easy to extend VFS with a new protocol, similar to what we've done with Assem bled and Mem ory.
All you need is a combination of VFSContexFactory, VFSContext, VirtualFileHandler,
FileHandlerPlugin, and URLStream Handler implementations. T he VFSContextFactory is
trivial, while the others depend on the complexity of your task. You could implement rar, tar, gzip, or
even rem ote access.
After implementing a new protocol, register the new VFSContextFactory with VFSContextFactoryLocator.
8.5. Features
One of the first major problems the Microcontainer developers faced was proper usage of nested
resources, more specifically nested jar files: For example, normal ear deployments:
88
Chapitre 8. The Virtual File System
gem a.ear/ui.war/WEB-INF/lib/struts.jar.
In order to read contents of struts.jar we have two options:
handle resources in memory
create top level temporary copies of nested jars, recursively
T he first option is easier to implement, but it's very memory-consuming, requiring potentially large
applications to reside in memory. T he other approach leaves behind a large number of temporary files,
which should be invisible to the end user and therefore should disappear after undeployment.
Consider the following scenario: A user accesses a VFS URL instance, which points to some nested
resource.
T he way plain VFS would handle this is to re-create the entire path from scratch: it would unpack nested
resources over and over again. T his leads to a great number of temporary files.
T he Microcontainer avoids this by using VFSRegistry, VFSCache, and T em pInfo.
When you ask for VirtualFile over VFS (getRoot, not createNewRoot), VFS asks the VFSRegistry
implementation to provide the file. T he existing DefaultVFSRegistry first checks if a matching root
VFSContext exists for the provided URI. If it does, DefaultVFSRegistry first tries to navigate to the
existing T em pInfo (link to a temporary files), falling back to regular navigation if no such temporary file
exists. In this way you completely reuse any temporary files which have already been unpacked, saving
time and disk space. If no matching VFSContext is found in cache, the code will create a new
VFSCache entry and continue with default navigation.
Determining how the VFSCache handles cached VFSContext entries depends on the implementation
used. VFSCache is configurable via VFSCacheFactory. By default, nothing is cached, but there are a
few useful existing VFSCache implementations, using algorithms such as Least Recently Used
(LRU) or tim ed cache.
89
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Chapitre 9. La couche de chargement de classe
JBoss a toujours eu une façon unique de traiter les chargement de classes, et la nouvelle couche de
chargement de classes du Microcontainer n'est pas différente sur ce point. Le chargement de classes
est un complément additionnel que vous pouvez utiliser quand vous souhaitez procéder à un
chargement de classe non conventionnel par défaut. Avec l'augmentation des chargements de style
OSGi, et un certain nombre de nouvelles spécifications de chargement de classes de Java à l'horizon,
les changements apportés à la couche de chargement de classes de EAP 5.1 sont utiles et tombent à
point.
La couche de chargement de classes du Microcontainer est une couche abstraite. La plupart des
informations sont cachées derrière des méthodes privées ou des méthodes de package-privés, sans
compromis sur l'extensibilité ou la fonctionnalité possible dans les classes publiques ou avec les
méthodes qui font l'API. Cela signifie que vous codez en fonction de la politique et non pas en fonction
des informations du chargeur de classes.
Le projet de chargement de classes et divisé en 3 sous-projets
chargeur de classes
chargement de classes
chargement de classes-vfs
classloader contient une extension personnalisée java.lang.ClassLoader sans aucune
politique de chargement de classes particulière. Une politique de chargement de classes doit
comprendre des instructions sur l'endroit à partir duquel décharger et comment charger.
Classloading est une extension des mécanismes de dépendance du Microcontainer. Son
implémentation endorsée-VFS est classloading-vfs. Voir Chapitre 8, The Virtual File System pour
obtenir plus d'informations sur VFS.
9.1. Chargeur de classes
L'implémentation ClassLoader supporte les politiques complémentaires et consititue en elle-même une
classe finale, qui n'est pas sensée être modifiée. Pour écrire vos propres implémentations de
chargement de classe, écrire une politique ClassLoaderPolicy qui fournit un simple API pour trouver
les ressources et les classes, et pour spécifier d'autres règles associées au chargeur de classes.
Pour personnaliser le chargement de classes, instancier un ClassLoaderPolicy et enregistrez-le
avec ClassLoaderSystem pour créer un ClassLoader personnalisé. Vous pouvez également créer
un ClassLoaderDom ain pour partitionner le ClassLoaderSystem .
La couche ClassLoader inclut également l'implémentation du modèle DelegateLoader, du chargement
de classes, des filtres de ressource, et des politiques de délégation parent-enfant, etc...
L'exécution de JMX a permis d'exposer la stratégie utilisée pour chaque chargeur de classes. Il fournit
également des statistiques de chargement de classes et de des méthodes de débogage pour aider à
déterminer à partir d'où viennent les chargements.
90
Chapitre 9. La couche de chargement de classe
Exemple 9.1. Classe ClassLoaderPolicy
Le ClassLoaderPolicy contrôle la façon dont le chargement de classes opère.
public abstract class ClassLoaderPolicy extends BaseClassLoaderPolicy {
public DelegateLoader getExported()
public String[] getPackageNames()
protected List<? extends DelegateLoader> getDelegates()
protected boolean isImportAll()
protected boolean isCacheable()
protected boolean isBlackListable()
public abstract URL getResource(String path);
public InputStream getResourceAsStream(String path)
public abstract void getResources(String name, Set<URL> urls) throws
IOException;
protected ProtectionDomain getProtectionDomain(String className, String
path)
public PackageInformation getPackageInformation(String packageName)
public PackageInformation getClassPackageInformation(String className,
String packageName)
protected ClassLoader isJDKRequest(String name)
}
}
Voici deux exemples de ClassLoaderPolicy. Le premier extrait les ressources fondées sur des
expressions régulières, tandis que le second s'occupe des ressources chiffrées.
91
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 9.2. ClassLoaderPolicy avec Support d'expressions régulières
92
Chapitre 9. La couche de chargement de classe
public class RegexpClassLoaderPolicy extends ClassLoaderPolicy {
private VirtualFile[] roots;
private String[] packageNames;
public RegexpClassLoaderPolicy(VirtualFile[] roots)
{
this.roots = roots;
}
@Override
public String[] getPackageNames()
{
if (packageNames == null)
{
Set<String> exportedPackages = PackageVisitor.determineAllPackages(roots,
null, ExportAll.NON_EMPTY, null, null, null);
packageNames = exportedPackages.toArray(new String[exportedPackages.size()]);
}
return packageNames;
}
protected Pattern createPattern(String regexp)
{
boolean outside = true;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < regexp.length(); i++)
{
char ch = regexp.charAt(i);
if ((ch == '[' || ch == ']' || ch == '.') && escaped(regexp, i) == false)
{
switch (ch)
{
case '[' : outside = false; break;
case ']' : outside = true; break;
case '.' : if (outside) builder.append("\\"); break;
}
}
builder.append(ch);
}
return Pattern.compile(builder.toString());
}
protected boolean escaped(String regexp, int i)
{
return i > 0 && regexp.charAt(i - 1) == '\\';
}
public URL getResource(String path)
{
Pattern pattern = createPattern(path);
for (VirtualFile root : roots)
{
URL url = findURL(root, root, pattern);
if (url != null)
return url;
}
return null;
}
93
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
private URL findURL(VirtualFile root, VirtualFile file, Pattern pattern)
{
try
{
String path = AbstractStructureDeployer.getRelativePath(root, file);
Matcher matcher = pattern.matcher(path);
if (matcher.matches())
return file.toURL();
List<VirtualFile> children = file.getChildren();
for (VirtualFile child : children)
{
URL url = findURL(root, child, pattern);
if (url != null)
return url;
}
return null;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
public void getResources(String name, Set<URL> urls) throws IOException
{
Pattern pattern = createPattern(name);
for (VirtualFile root : roots)
{
RegexpVisitor visitor = new RegexpVisitor(root, pattern);
root.visit(visitor);
urls.addAll(visitor.getUrls());
}
}
private static class RegexpVisitor implements VirtualFileVisitor
{
private VirtualFile root;
private Pattern pattern;
private Set<URL> urls = new HashSet<URL>();
private RegexpVisitor(VirtualFile root, Pattern pattern)
{
this.root = root;
this.pattern = pattern;
}
public VisitorAttributes getAttributes()
{
return VisitorAttributes.RECURSE_LEAVES_ONLY;
}
public void visit(VirtualFile file)
{
try
{
String path = AbstractStructureDeployer.getRelativePath(root, file);
Matcher matcher = pattern.matcher(path);
if (matcher.matches())
94
Chapitre 9. La couche de chargement de classe
urls.add(file.toURL());
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
public Set<URL> getUrls()
{
return urls;
}
}
}
RegexpClassLoaderPolicy utilise un mécanisme simpliste pour trouver les ressources qui
correspondent. Les implémentations réelles sont normalement plus complètes et plus élégantes.
public class RegexpService extends PrintService {
public void start() throws Exception
{
System.out.println();
ClassLoader cl = getClass().getClassLoader();
Enumeration<URL> urls = cl.getResources("config/[^.]+\\.[^.]{1,4}");
while (urls.hasMoreElements())
{
URL url = urls.nextElement();
print(url.openStream(), url.toExternalForm());
}
}
}
Le service regexp utilise des modèles d'expression config/[^.]+\\.[^.]{1,4 } pour lister les
ressources sous le répertoire/ config/. La longueur du suffixe est limitée, de façon à ce que les
noms de fichiers comme excluded.properties soient ignorés.
95
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 9.3. ClassLoaderPolicy avec support de chiffrement
public class CrypterClassLoaderPolicy extends VFSClassLoaderPolicy {
private Crypter crypter;
public CrypterClassLoaderPolicy(String name, VirtualFile[] roots,
VirtualFile[] excludedRoots, Crypter crypter) {
super(name, roots, excludedRoots);
this.crypter = crypter;
}
@Override
public URL getResource(String path) {
try
{
URL resource = super.getResource(path);
return wrap(resource);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
@Override
public InputStream getResourceAsStream(String path) {
InputStream stream = super.getResourceAsStream(path);
return crypter.crypt(stream);
}
@Override
public void getResources(String name, Set<URL> urls) throws IOException {
super.getResources(name, urls);
Set<URL> temp = new HashSet<URL>(urls.size());
for (URL url : urls)
{
temp.add(wrap(url));
}
urls.clear();
urls.addAll(temp);
}
protected URL wrap(URL url) throws IOException {
return new URL(url.getProtocol(), url.getHost(), url.getPort(),
url.getFile(), new CrypterURLStreamHandler(crypter));
}
}
Exemple 9.3, « ClassLoaderPolicy avec support de chiffrement » montre comment encrypter les JAR.
Vous pouvez configurer quelles ressources encrypter pour spécifier un filtre. Ici, tout est chiffré, mis à
part les contenus du répertoire MET A-INF/.
96
Chapitre 9. La couche de chargement de classe
public class EncryptedService extends PrintService {
public void start() throws Exception
{
ClassLoader cl = getClass().getClassLoader();
URL url = cl.getResource("config/settings.txt");
if (url == null)
throw new IllegalArgumentException("No such settings.txt.");
InputStream is = url.openStream();
print(is, "Printing settings:\n");
is = cl.getResourceAsStream("config/properties.xml");
if (is == null)
throw new IllegalArgumentException("No such properties.xml.");
print(is, "\nPrinting properties:\n");
}
}
Ce service affiche les contenus de deux fichiers de configuration. Il montre que le décryptage de toute
ressource chiffrée est cachée derrière la couche de chargement de classes.
Pour pouvoir tester cela, vous pourrez soit chiffrer le module de la politique vous-même ou en utiliser
une qui est chiffrée. Pour actionner tout cela, vous aurez besoin d'associer correctement
EncryptedService à ClassLoaderSystem et aux déployeurs.
On discute le partitionnement du ClassLoaderSystem dans un chapitre suivant.\n
9.2. Chargement de classes
Au lieu d'utiliser l'abstraction ClassLoader directement, vous pouvez créer les modules
ClassLoading qui contiennent des déclarations des dépendances du ClassLoader. Une fois que
les dépendances ont été spécifiées, les politiques ClassLoaderPolicy sont construites et cablées
en fonction.
Pour faciliter la définition des ClassLoaders avant qu'elles n'existent, l'abstraction inclut un modèle de
ClassLoadingMetaData.
Le ClassLoadingMetaData peut être présenté comme un Managed Object du nouveau service de
profil JBoss EAP. Cela aide les administrateurs de système à gérer des informations de politique plus
abstraits que les informations d'implémentation.
97
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 9.4 . ClassLoadingMetaData présentées comme Managed Object
public class ClassLoadingMetaData extends NameAndVersionSupport {
/** The serialVersionUID */
private static final long serialVersionUID = -2782951093046585620L;
/** The classloading domain */
private String domain;
/** The parent domain */
private String parentDomain;
/** Whether to make a subdeployment classloader a top-level classloader */
private boolean topLevelClassLoader = false;
/** Whether to enforce j2se classloading compliance */
private boolean j2seClassLoadingCompliance = true;
/** Whether we are cacheable */
private boolean cacheable = true;
/** Whether we are blacklistable */
private boolean blackListable = true;
/** Whether to export all */
private ExportAll exportAll;
/** Whether to import all */
private boolean importAll;
/** The included packages */
private String includedPackages;
/** The excluded packages */
private String excludedPackages;
/** The excluded for export */
private String excludedExportPackages;
/** The included packages */
private ClassFilter included;
/** The excluded packages */
private ClassFilter excluded;
/** The excluded for export */
private ClassFilter excludedExport;
/** The requirements */
private RequirementsMetaData requirements = new RequirementsMetaData();
/** The capabilities */
private CapabilitiesMetaData capabilities = new CapabilitiesMetaData();
... setters & getters
98
Chapitre 9. La couche de chargement de classe
Exemple 9.5, « API ClassLoading défini dans XML » et Exemple 9.6, « API ClassLoading défini dans
Java » nous montre l'API ClassLoading (chargement de classes) défini dans XML et Java
respectivement.
Exemple 9.5. API ClassLoading défini dans XML
<classloading xmlns="urn:jboss:classloading:1.0"
name="ptd-jsf-1.0.war"
domain="ptd-jsf-1.0.war"
parent-domain="ptd-ear-1.0.ear"
export-all="NON_EMPTY"
import-all="true"
parent-first="true"/>
Exemple 9.6. API ClassLoading défini dans Java
ClassLoadingMetaData clmd = new ClassLoadingMetaData();
if (name != null)
clmd.setDomain(name + "_Domain");
clmd.setParentDomain(parentDomain);
clmd.setImportAll(true);
clmd.setExportAll(ExportAll.NON_EMPTY);
clmd.setVersion(Version.DEFAULT_VERSION);
Vous pouvez ajouter ClaasLoadingMetaData à votre déploiement soit par programmation, ou
déclarativement, via jboss-classloading.xm l.
Exemple 9.7. Ajouter ClassLoadingMetaData en utilisant jboss-classloading.xm l
<classloading xmlns="urn:jboss:classloading:1.0"
domain="DefaultDomain"
top-level-classloader="true"
export-all="NON_EMPTY"
import-all="true">
</classloading>
Le DefautDomain (domaine par défaut) est partagé par toutes les applications qui ne définissent pas
leur propre domaine.
99
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 9.8. Isolations typiques niveau-domaine
<classloading xmlns="urn:jboss:classloading:1.0"
domain="IsolatedDomain"
export-all="NON_EMPTY"
import-all="true">
</classloading>
Exemple 9.9. Isolation avec un parent spécifique
<classloading xmlns="urn:jboss:classloading:1.0"
domain="IsolatedWithParentDomain"
parent-domain="DefaultDomain"
export-all="NON_EMPTY"
import-all="true">
</classloading>
Exemple 9.10. Incompatibilité avec j2seClassLoadingCompliance
<classloading xmlns="urn:jboss:classloading:1.0"
parent-first="false">
</classloading>
Les déploiements .war utilisent cette méthode par défaut. Au lieu de faire des recherches parentd'abord, vous pouvez chercher tout d'abord vos propres ressources.
Exemple 9.11. Implémentation OSGi typique
<classloading xmlns="urn:jboss:classloading:1.0">
<requirements>
<package name="org.jboss.dependency.spi"/>
</requirements>
<capabilities>
<package name="org.jboss.cache.api"/>
<package name="org.jboss.kernel.spi"/>
</capabilities>
</classloading>
100
Chapitre 9. La couche de chargement de classe
Exemple 9.12. Importer et exporter des modules et des bibliothèques complètes, au lieu
de packages à fine granularité.
<classloading xmlns="urn:jboss:classloading:1.0">
<requirements>
<module name="jboss-reflect.jar"/>
</requirements>
<capabilities>
<module name="jboss-cache.jar"/>
</capabilities>
</classloading>
<classloading xmlns="urn:jboss:classloading:1.0">
<requirements>
<package name="si.acme.foobar"/>
<module name="jboss-reflect.jar"/>
</requirements>
<capabilities>
<package name="org.alesj.cl"/>
<module name="jboss-cache.jar"/>
</capabilities>
</classloading>
Vous pouvez également mélanger les types d'exigences et les types de capacités, à l'aide de packages
et de modules.
Le sous-projet de chargement de classes utilise une toute petite implémentation de modèle-visiteurressource.
Dans le projet ClassLoader, la connexion entre le déploiement et le chargement de classes est fait
par l'intermédiaire de la classe Module, qui contient toutes les informations demandées en vue
d'appliquer correctement les restrictions sur le modèle visiteur, comme le filtrage.
101
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 9.13. Les interfaces ResourceVisitor et ResourceContext
public interface ResourceVisitor {
ResourceFilter getFilter();
void visit(ResourceContext resource);
}
public interface ResourceContext {
URL getUrl();
ClassLoader getClassLoader();
String getResourceName();
String getClassName();
boolean isClass();
Class<?> loadClass();
InputStream getInputStream() throws IOException;
byte[] getBytes() throws IOException;
}
Pour utiliser le module, instancier votre instance ResourceVisitor et passez-le à la méthode
Module::visit. Cette fonctionnalité est utilisée dans le framework de déploiement pour indexer
l'utilisation des annotations dans les déploiements.
9.3. ClassLoading VFS
Ces exemples fournissent une implémentation de la politique ClassLoaderPolicy qui utilise un projet
JBoss Virtual File System pour charger des classes et des ressources. Vous pouvez utiliser cette idée
directement ou en combinaison à un framework de chargement de classes.
En option, vous pouvez installer des modules dans la configuration du Microcontainer.
102
Chapitre 9. La couche de chargement de classe
Exemple 9.14 . Déployeur du module de chargement de classes.
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<classloader name="anys-classloader" xmlns="urn:jboss:classloader:1.0" importall="true" domain="Anys" parent-domain="DefaultDomain">
<capabilities>
<package name="org.jboss.test.deployers.vfs.reflect.support.web"/>
</capabilities>
<root>${jboss.tests.url}</root>
</classloader>
<bean name="AnyServlet"
class="org.jboss.test.deployers.vfs.reflect.support.web.AnyServlet">
<classloader><inject bean="anys-classloader:0.0.0"/></classloader>
</bean>
</deployment>
La classe VFSClassLoaderFactory transforme le déployeur XML en
VFSClassLoaderPolicyModule, qui crée l'instance ClassLoader. Vous pourrez alors utiliser cette
nouvelle instance de ClassLoader avec vos beans.
Note
VFSClassLoaderFactoryétend ClassLoadingMetaData, donc tous les exemples liés à
ClassLoadingMetaData s'appliquent dans ce cas également.
103
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Chapitre 10. The Virtual Deployment Framework
T he new Virtual Deployment Framework (VDF) is an improved way to manage deployers in the
Microcontainer. T his chapter details some of its useful features.
10.1. Agnostic Handling of Deployment Types
T he traditional type of virtual deployment is based on classes which already exist in a shared classspace or domain. In this case, the end product is a new service installed onto the server from your main
client. T he traditional way to do this is to upload a descriptor file. T he new VDF simplifies this process by
passing over the bytes and serializing them into a Deploym ent instance.
T he other type of deployment, which extends the first one, is a plain file-system-based deployment,
backed up by Microcontainer VFS. T his approach is described in more detail in Chapitre 8, The Virtual
File System.
10.2. Separation of Structure Recognition From Deployment
lifecycle logic
In order to do any real work on top of a deployment, you must first understand its structure, including its
classpaths and metadata locations.
Metadata locations include the configuration files such as m y-jboss-beans.xm l, web.xm l, ejbjar.xm l. Classpaths are classloader roots, such as WEB-INF/classes or m yapp.ear/lib.
Bearing the structure in mind, you can proceed to actual deployment handling.
A T ypical Deployment Lifecycle
1. T he MainDeployer passes the deployment to the set of StructuralDeployers for
recognition, and receives back a Deployment context.
2. Next, the MainDeployer passes the resulting Deployment context to the Deployers for
handling by the appropriate Deployer.
In this way, the MainDeployer is a broker with the responsibility of deciding which Deployers to use.
In the case of virtual or programmatic deployment, an existing predetermined StructureMetaData
information reads the structure information and handles it in one of the ways explained in Handling
StructuredMetaData Information.
Handling StructuredMetaData Information
VFS-based deployments
the structure recognition is forwarded to a set of StructureDeployers.
JEE-specification-defined structures
we have matching StructureDeployer implementations:
EarStructure
WarStructure
JarStructure
104
Chapitre 10. The Virtual D eployment Framework
DeclarativeStructures
looks for MET A-INF/jboss-structure.xm l file inside your deployment, and parses it to
construct a proper StructureMetaData.
FileStructures
only recognizes known configuration files, such as files like -jboss-beans.xm l or service.xm l.
Exemple 10.1. An example of jboss-structure.xm l
<structure>
<context
comparator="org.jboss.test.deployment.test.SomeDeploymentComparatorTop">
<path name=""/>
<metaDataPath>
<path name="META-INF"/>
</metaDataPath>
<classpath>
<path name="lib" suffixes=".jar"/>
</classpath>
</context>
</structure>
In the case of EarStructure, first recognize a top level deployment, then recursively process subdeployments.
You can implement a custom StructureDeployer with the help of the generic GroupingStructure
class provided by the generic StructureDeployer interface.
After you have a recognized deployment structure, you can pass it to real deployers. T he Deployers
object knows how to deal with the real deployers, using a chain of deployers per Deploym entStage.
105
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Exemple 10.2. Deployment Stages
public interface DeploymentStages {
/** The not installed stage - nothing is done here */
DeploymentStage NOT_INSTALLED = new DeploymentStage("Not Installed");
/** The pre parse stage - where pre parsing stuff can be prepared; altDD,
ignore, ... */
DeploymentStage PRE_PARSE = new DeploymentStage("PreParse", NOT_INSTALLED);
/** The parse stage - where metadata is read */
DeploymentStage PARSE = new DeploymentStage("Parse", PRE_PARSE);
/** The post parse stage - where metadata can be fixed up */
DeploymentStage POST_PARSE = new DeploymentStage("PostParse", PARSE);
/** The pre describe stage - where default dependencies metadata can be
created */
DeploymentStage PRE_DESCRIBE = new DeploymentStage("PreDescribe",
POST_PARSE);
/** The describe stage - where dependencies are established */
DeploymentStage DESCRIBE = new DeploymentStage("Describe", PRE_DESCRIBE);
/** The classloader stage - where classloaders are created */
DeploymentStage CLASSLOADER = new DeploymentStage("ClassLoader", DESCRIBE);
/** The post classloader stage - e.g. aop */
DeploymentStage POST_CLASSLOADER = new DeploymentStage("PostClassLoader",
CLASSLOADER);
/** The pre real stage - where before real deployments are done */
DeploymentStage PRE_REAL = new DeploymentStage("PreReal", POST_CLASSLOADER);
/** The real stage - where real deployment processing is done */
DeploymentStage REAL = new DeploymentStage("Real", PRE_REAL);
/** The installed stage - could be used to provide valve in future? */
DeploymentStage INSTALLED = new DeploymentStage("Installed", REAL);
}
Preexisting deployment stages are mapped to the Microcontainer's built-in controller states. T hey
provide a deployment-lifecycle-centric view of generic controller states.
Inside Deployers, the deployment is converted into the Microcontainer's component
Deploym entControllerContext. T he Microcontainer's state machine handles dependencies.
Deployments are handled sequentially by deployment stage. For each deployer, the entire deployed
hierarchy order is handled, using the deployer's parent-first property. T his property is set to true
by default.
You can also specify which hierarchy levels your deployer handles. You can choose all, top level,
com ponents only, or no com ponents.
T he way the Microcontainer handles component models and dependency handling applies here as well.
If there are unresolved dependencies, the deployment will wait in the current state, potentially reporting
an error if the current state is not the required state.
106
Chapitre 10. The Virtual D eployment Framework
an error if the current state is not the required state.
Adding a new deployer is accomplished by extending one of the many existing helper deployers.
Some deployers actually need VFS backed deployment, while others can use a general deployment. In
most cases the parsing deployers are the ones that need VFS backing.
Avertissement
Also be aware that deployers run recursively through every deployment, sub-deployment, and
component. Your code needs to determine, as early in the process as possible, whether the
deployer should handle the current deployment or not.
Exemple 10.3. Simple Deployer which Outputs Information About Its Deployment
public class StdioDeployer extends AbstractDeployer {
public void deploy(DeploymentUnit unit) throws DeploymentException
{
System.out.println("Deploying unit: " + unit);
}
@Override
public void undeploy(DeploymentUnit unit)
{
System.out.println("Undeploying unit: " + unit);
}
}
Add this description into one of the -jboss-beans.xm l files in deployers/ directory in JBoss
Application Server, and MainDeployerIm pl bean will pick up this deployer via the Microcontainer's
IoC callback handling.
Exemple 10.4 . Simple Deployment Descriptor
<bean name="StdioDeployer" class="org.jboss.acme.StdioDeployer"/>
10.3. Natural Flow Control in the form of Attachments
VDF includes a mechanism called attachments, which facilitates the passing of information from one
deployer to the next. Attachments are implemented as a slightly-enhanced java.util.Map, whose
entries each represent an attachment.
Some deployers are producers, while others are consumers. T he same deployer can also perform both
functions. Some deployers create metadata or utility instances, putting them into the attachments map.
Other deployers only declare their need for these attachments and pull the data from the attachments
map, before doing additional work on that data.
Natural order refers to the way that deployers are ordered. A common natural order uses the relative
terms before and after. However, with the attachments mechanism already in place, you can order
deployers by the way in which they produce and/or consume the attachments.
107
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Each attachment has a key, and deployers pass keys to the attachments they produce. If the deployer
produces an attachment, then that key is called output. If the deployer consumes an attachment, then
that key is called input.
Deployers have ordinary inputs and required inputs. Ordinary inputs are only used to help determine the
natural order. Required inputs also help determine order, but they have another function too. T hey help
to determine if the deployer is actually relevant for the given deployment, by checking to see if an
attachment corresponding to that required input exists in the attachments map.
Avertissement
While relative ordering is still supported, it is considered bad practice, and could be desupported
in future releases.
10.4. Client, User, and Server Usage and Implementation Details
T hese features hide the implementation details, making the usage less error-prone, while at the same
time streamlining the development process.
T he goal is for clients to only see a Deployment API, while developers see a DeploymentUnit, and server
implementation details are contained in a DeploymentContext. Only the necessary information is
exposed to a particular level of deployment's lifecycle.
Components have already been mentioned as part of deployers' hierarchy handling. While top level
deployment and sub-deployments are a natural representation of the deployment's structure hierarchy,
components are a new VDF concept. T he idea of components is that they have a 1:1 mapping with the
ControllerContexts inside the Microcontainer. See Why Components Map 1:1 with the
ControllerContexts for the reasons behind this assertion.
Why Components Map 1:1 with the ControllerContexts
Nommage
T he component unit's name is the same as the ControllerContext's name.
get*Scope() and get*MetaData()
return the same MDR context that will be used by the Microcontainer for that instance.
IncompleteDeploymentException (IDE)
In order for the IDE to print out what dependencies are missing for a deployment, it needs to
know the ControllerContext names. It discovers the name by collecting the Component
DeploymentUnit's names in Component Deployers that specify them, such as
BeanMetaDataDeployer or the setUseUnitNam e() method in
AbstractRealDeployer.
10.5. Single State Machine
All Microcontainer components are handled by a single entry point, or single state machine. Deployments
are no exception.
108
Chapitre 10. The Virtual D eployment Framework
You can take advantage of this feature by using the jboss-dependency.xm l configuration file in your
deployments.
Exemple 10.5. jboss-dependency.xml
<dependency xmlns="urn:jboss:dependency:1.0">
<item whenRequired="Real" dependentState="Create">TransactionManager</item>
(1)
<item>my-human-readable-deployment-alias</item> (2)
</dependency>
Note the artificial call-outs in the XML: (1) and (2).
(1) shows how to describe dependency on another service. T his example requires
T ransactionManager to be created before the deployment is in the 'Real' stage.
(2) is a bit more complex, since you are missing additional information. By default, deployment names
inside the Microcontainer are URI names, which makes typing them by hand an error prone
proposition. So, in order to be able to easily declare dependence on other deployments, you need an
aliasing mechanism to avoid URI names. You can add a plain text file named aliases.txt into your
deployment. Each line of the file contains an alias, giving a deployment archive one or more simple
names used to refer to it.
10.6. Scanning Classes for Annotations
Current JEE specifications reduce the number of configuration files, but the container is now required to
do most of the work using @annotations. In order to get @annotation info, containers must scan
classes. T his scanning creates a performance penalty.
But to reduce the amount of scanning, the Microcontainer provides another descriptor hook, by means of
jboss-scanning.xm l.
Exemple 10.6. jboss-scanning.xml
<scanning xmlns="urn:jboss:scanning:1.0">
<path name="myejbs.jar">
<include name="com.acme.foo"/>
<exclude name="com.acme.foo.bar"/>
</path>
<path name="my.war/WEB-INF/classes">
<include name="com.acme.foo"/>
</path>
</scanning>
T his example shows a simple description of relative paths to include or exclude when scanning for
Java Enterprise Edition version 5 and greater annotated metadata information.
109
JBoss Enterprise Application Platform 5 Guide d'utilisateur de JBoss Microcontainer
Historique de révision
Version 5.1.0-4 .4 00
Rebuild with publican 4.0.0
2013-10-31
Rüdiger Landmann
Version 5.1.0-4
Rebuild for Publican 3.0
2012-07-18
Anthony T owns
Version 5-1
Wed Sep 15 2010
Misty Stanley-Jones
JBPAPP-5076 - Répare les erreurs de correspondance entre les exemples et le texte
Nouveau numéro de version en accord avec les nouveaux besoins du contrôle de version
Révisé pour JBoss Enterprise Application Platform 5.1.0.GA.
110