Guide de développement
À utiliser dans Red Hat JBoss Enterprise Application Platform 6
Red Hat Customer Content Services
Résumé
Chapitre 1. Introduction au développement d'applications
1.1. Introduction
1.1.1. Red Hat JBoss Enterprise Application Platform 6
1.2. Conditions préalables
1.2.1. Familiarisez vous avec Java Enterprise Edition 6
1.2.1.1. Les Profils EE 6
1.2.1.2. Web Profil de Java Enterprise Edition 6
Conditions préalables de Java EE 6 Web Profile
- Java Platform, Enterprise Edition 6
Technologies Java Web
- Servlet 3.0 (JSR 315)
- JSP 2.2 et Expression Language (EL) 1.2
- JavaServer Faces (JSF) 2.1 (JSR 314)
- Java Standard Tag Library (JSTL) for JSP 1.2
- Débogage du support pour les autres langages 1.0 (JSR 45)
Enterprise Application Technologies
- Contexts and Dependency Injection (CDI) (JSR 299)
- Injection de dépendance dans Java (JSR 330)
- Enterprise JavaBeans 3.1 Lite (JSR 318)
- Java Persistence API 2.0 (JSR 317)
- Annotations communes de la Plateforme Java 1.1 (JSR 250)
- Java Transaction API (JTA) 1.1 (JSR 907)
- Bean Validation (JSR 303)
1.2.1.3. Java Enterprise Edition 6 Full Profile
Items inclus dans EE 6 Full Profile
- EJB 3.1 (not Lite) (JSR 318)
- Java EE Connector Architecture 1.6 (JSR 322)
- Java Message Service (JMS) API 1.1 (JSR 914)
- JavaMail 1.4 (JSR 919)
Technologies Service Web
- Jax-RS RESTful Web Services 1.1 (JSR 311)
- Implémentation d'Enterprise Web Services 1.3 (JSR 109)
- JAX-WS Java API for XML-Based Web Services 2.2 (JSR 224)
- Java Architecture pour XML Binding (JAXB) 2.2 (JSR 222)
- Web Services Metadata pour Java Platform (JSR 181)
- Les API Java pour XML-based RPC 1.1 (JSR 101)
- Les API Java pour XML Messaging 1.3 (JSR 67)
- Java API pour les Registres XML (JAXR) 1.0 (JSR 93)
Technologies de Gestion et de Sécurité
- Interface Fournisseur Service Java Authentification pour Conteneurs 1.0 (JSR 196)
- Contrat Java Authentication Contract pour les Conteneurs 1.3 (JSR 115)
- Déploiement Application Java EE 1.2 (JSR 88)
- J2EE Management 1.1 (JSR 77)
1.2.2. Les modules et le système de chargement de la nouvelle classe modulaire de JBoss EAP 6.
1.2.2.1. Modules
- Modules statiques
- Les modules statiques sont prédéfinis dans le répertoire
EAP_HOME/modules/
du serveur d'applications. Chaque sous-répertoire représente un module et contient un fichier de configuration (module.xml
) et tout fichier JAR requis. Le nom du module est défini dans le fichiermodule.xml
. Tous les API fournis par le serveur de l'application sont des modules statiques, y compris les API Java EE, et les autres API comme JBoss Logging.Exemple 1.1. Exemple de fichier module.xml
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.15.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
Le nom du module,com.mysql
, doit correspondre à la structure du répertoire du module.Les modules fournis dans les distributions JBoss EAP se trouvent dans un répertoiresystem
se trouvant lui-même dans le répertoireJBOSS_HOME/modules
. Cela les rend séparés de tout module fourni par une tierce partie.Tout produit mis en couche de Red Hat, se superposant sur JBoss EAP 6.1 ou version supérieure installera également leurs modules dans le répertoiresystem
.La création de modules statiques personnalisés peut être utile si plusieurs applications sont déployées sur un même serveur utilisant les mêmes bibliothèques de tierce partie. Au lieu d'un regroupement de ces bibliothèques pour chaque application, un module contenant ces bibliothèques peut être créé et installé par l'administrateur JBoss. Les applications peuvent ensuite déclarer une dépendance explicite sur les modules statiques personnalisés.Les utilisateurs doivent s'assurer que les modules personnalisés soient installés dans le répertoireJBOSS_HOME/modules
, en utilisant un répertoire par couche de modules. Cela garantit que les versions personnalisées de modules qui existent déjà dans le répertoiresystem
soient bien chargées à la place des versions fournies. Ainsi, les modules utilisateur auront la priorité sur les modules fournis par le système.Si vous utilisez la variable d'environnementJBOSS_MODULE_PATH
pour changer les emplacements où JBoss EAP cherche les modules, le produit ira chercher dans une structure de sous-répertoiresystem
dans un des emplacements spécifiés. Une structure de sous-répertoiresystem
doit exister quelquepart dans les emplacements spécifiés dansJBOSS_MODULE_PATH
. - Modules dynamiques
- Les modules dynamiques sont créés et chargés par le serveur d'application pour chaque déploiement JAR ou WAR (ou sous-déploiement d'un EAR). Le nom d'un module dynamique est dérivé du nom de l'archive déployée. Comme les déploiements sont chargés sous forme de modules, ils peuvent configurer des dépendances et peuvent être utilisés comme dépendances par d'autres déploiements.
1.3. Installer l'environnement de développement
1.3.1. Télécharger et installer Red Hat JBoss Developer Studio (JDBS)
1.3.1.1. Installer Red Hat JBoss Developer Studio (JDBS)
1.3.1.2. Téléchargez Red Hat JBoss Developer Studio 7.1
- Visitez https://access.redhat.com/.
- Sélectionnez Téléchargements du menu en haut de la page.
- Cherchez
Red Hat JBoss Developer Studio
dans la liste et cliquez dessus. - Sélectionnez la version appropriée et cliquez sur Télécharger.
1.3.1.3. Installer Red Hat JBoss Developer Studio 7.1
- Conditions préalables :
Procédure 1.1. Installer Red Hat JBoss Developer Studio 7.1
- Ouvrir un terminal.
- Aller dans le répertoire qui contient le fichier téléchargé
.jar
. - Exécuter la commande suivante pour lancer le GUI d'installation.
java -jar jbdevstudio-build_version.jar
- Cliquer sur Suivant pour commencer le processus d'installation.
- Sélectionner I accept the terms of this license agreement (J'accepte les conditions de licence) et cliquer sur Suivant.
- Ajuster le chemin d'accès de l'installation et cliquer sur Next.
Note
Si le dossier de chemin d'installation n'existe pas, vous verrez une invite. Cliquer alors sur Ok pour créer le dossier. - Choisir une JVM, ou bien conserver la JVM sélectionnée par défaut, et cliquer sur Next.
- Ajouter une plateforme d'applications disponible, et cliquer sur Next.
- Vérifier les informations d'installation et cliquer sur Next.
- Cliquer sur Next une fois le processus d'installation terminé.
- Configurer les raccourcis bureau pour Red Hat JBoss Developer Studio et cliquer sur Next (suivant).
- Cliquer sur le bouton Done.
1.3.1.4. Démarrer Red Hat JBoss Developer Studio
- Conditions préalables :
Procédure 1.2. Commande de démarrage de Red Hat JBoss Developer Studio
- Ouvrir un terminal.
- Aller dans le répertoire d'installation.
- Lancer la commande suivante pour démarrer JBoss Developer Studio :
[localhost]$ ./jbdevstudio
1.3.1.5. Ajouter le serveur de JBoss EAP en utilisant Define New Server
Procédure 1.3. Ajouter le serveur
- Ouvrir l'onglet Servers. S'il n'y a pas d'onglet Servers, l'ajouter au panneau comme suit :
- Cliquer sur Window → Show View → Other....
- Sélectionner Serveurs à partir du dossier Server et cliquer sur OK.
- Cliquer sur le lien create a new server ou bien cliquer à droite dans le panneau vide Serveur, et sélectionner New → Server.
Figure 1.1. Ajouter un nouveau serveur - Aucun serveur disponible
- Étendre JBoss Enterprise Middleware et choisir JBoss Enterprise Application Platform 6.1+. Puis, cliquer sur Next pour créer le JBoss Runtime et définir le serveur. La prochaine fois que vous définirez un nouveau serveur, ce dialogue affichera un menu de sélection Server runtime environment avec la nouvelle définition de runtime.
Figure 1.2. Définir un nouveau serveur
- Saisir un nom comme "JBoss EAP 6.3 Runtime". Sous Home Directory, cliquer sur Browse puis, naviguer vers l'emplacement de l'installation de JBoss EAP. Puis, cliquer sur Next.
Figure 1.3. Ajouter un environnement de runtime du nouveau serveur
- Sur cet écran, vous définissez le comportement de serveur. Vous pouvez démarrer le serveur manuellement ou laisser Red Hat JBoss Developer Studio le gérer pour vous. Vous pouvez également définir un serveur distant pour le déploiement et déterminer si vous souhaitez exposer le port de gestion pour ce serveur, par exemple, si vous avez besoin de le connecter en utilisant JMX. Dans cet exemple, supposons que le serveur est local et que vous souhaitiez que Red Hat JBoss Developer Studio gère votre serveur sans que vous ayiez besoin de vérifier quoi que ce soit. Cliquer sur Next.
Figure 1.4. Définir le nouveau comportement du serveur de JBoss
- Cet écran vous permet de configurer les projets existants pour le nouveau serveur. Puisque vous n'avez pas de projets à ce stade, cliquez sur Terminé.
Figure 1.5. Modifier les ressources dans le nouveau serveur de JBoss
Le serveur de JBoss EAP est listé dans l'onglet Servers.

Figure 1.6. Le server apparaît sur la liste de serveurs
1.4. Exécuter votre première application
1.4.1. Télécharger les exemples de codes Quickstart
1.4.1.1. Accès aux Quickstarts
JBoss EAP 6 contient une série d'exemples quickstart conçus pour aider les utilisateurs à commencer à rédiger des applications en utilisant les technologies Java EE 6.
Conditions préalables
- Maven 3.0.0 ou versions plus récentes. Pour en savoir plus sur l'installation de Maven, veuillez consulter http://maven.apache.org/download.html.
- Le référentiel JBoss EAP 6.3 Maven est disponible en ligne, donc il n'est pas utile de le télécharger ou de l'installer localement. Si vous envisagez de l'utiliser en ligne, passer à l'étape suivante. Si vous préférez l'installer dans un référentiel local, consulter : Section 2.2.3, « Installer le référentiel Maven de JBoss EAP 6 localement ».
Procédure 1.4. Télécharger les Quickstarts
- Ouvrir un navigateur web, et accéder à cet URL: https://access.redhat.com/jbossnetwork/restricted/listSoftware.html?product=appplatform.
- Trouver "Quickstarts" dans la liste.
- Cliquer sur le bouton Downloads pour télécharger un fichier ZIP contenant les exemples.
- Décompresser l'archive dans un répertoire de votre choix.
Les exemples de Java EE Quickstart ont été téléchargés et décompressés. Veuillez consulter le fichier README.md
dans le répertoire supérieur des archives Quickstart pour des instructions concernant le déploiement de chaque quickstart.
1.4.2. Exécuter les Quickstarts
1.4.2.1. Exécuter les quickstarts (démarrages rapides) dans Red Hat JBoss Developer Studio
Procédure 1.5. Importer les quickstarts dans Red Hat JBoss Developer Studio
Important
- Si vous ne l'avez pas encore fait, Section 2.3.2, « Configurer le référentiel JBoss EAP 6 Platform Maven Repository par les paramètres de configuration de Maven ».
- Démarrer Red Hat JBoss Developer Studio.
- À partir du menu, sélectionner Fichier → Importer.
- Dans la liste sélectionnée, choisir Maven → Projets Maven existants, puis cliquer sur Suivant.
Figure 1.7. Importer les projets Maven existants
- Naviguer vers le répertoire du quickstart que vous souhaitez tester, comme
helloworld
, et cliquer sur OK. La zone de liste Projects verra apparaître le fichierpom.xml
du projet quickstart sélectionné.Figure 1.8. Sélectionner les projets Maven
- Cliquer sur Terminé.
Procédure 1.6. Générer et déployer le Quickstart helloworld
helloworld
est un des quickstarts les plus simples et représente une bonne façon de vérifier que le serveur JBoss est configuré et exécute correctement.
- Si vous ne voyez pas un onglet Servers, ajoutez le au panneau comme suit :
- Cliquer sur Window → Show View → Other....
- Sélectionner Servers à partir du dossier Server et cliquer sur OK.
- Cliquer à droite sur
jboss-helloworld
sur l'onglet Project Explorer, puis sélectionner Run As. On vous présentera une liste de choix. Sélectionner Run on Server.Figure 1.9. Run As - Run on Server
- Sélectionner jboss-eap-6.3 de la liste de serveurs, et cliquer sur Next.
Figure 1.10. Exécuter sur le serveur
- L'écran suivant affiche les ressources qui sont configurées sur le serveur. Le quickstart de
jboss-helloworld
est configuré pour vous. Cliquer sur Finish pour déployer le quickstart.Figure 1.11. Modifier les ressources configurées sur le serveur
- Vérifier les résultats.
- Dans l'onglet
Server
, le statut de JBoss EAP 6.3 Runtime Server passe à[Started, Republish]
. - L'onglet Console du serveur affiche des messages détaillant le démarrage du serveur JBoss EAP 6.3 et le déploiement du quickstart helloworld.
- Un onglet helloworld apparaîtra avec l'URL http://localhost:8080/jboss-helloworld/HelloWorld et le texte "Hello World!".
- Les messages suivants de la Console confirment le déploiement du fichier
jboss-helloworld.war
:JBAS018210: Register web context: /jboss-helloworld JBAS018559: Deployed "jboss-helloworld.war" (runtime-name : "jboss-helloworld.war")
Le contexte web enregistré se rajoute àhttp://localhost:8080
pour fournir l'URL utilisé pour accéder à l'application qui est déployée.
- Pour vérifier que le Quickstart
helloworld
a été déployé correctement dans le serveur JBoss, ouvrir le navigateur web, et accéder à l'application dans l'URL : http://localhost:8080/jboss-helloworld
1.4.2.2. Exécuter les quickstarts par la Ligne de commande
Procédure 1.7. Générer et déployer les quickstarts par la Ligne de commande
- Si vous ne l'avez pas encore fait, Section 2.3.2, « Configurer le référentiel JBoss EAP 6 Platform Maven Repository par les paramètres de configuration de Maven ».
- Vérifier le fichier
README.html
qui se trouve dans le répertoire racine des quickstarts.Ce fichier contient des informations générales sur les conditions préalables de systèmes, sur la façon de configurer Maven, comment ajouter des utilisateurs, et comment exécuter les quickstarts. Lisez attentivement avant de commencer.Il contient également un tableau qui répertorie les quickstarts disponibles. Le tableau répertorie chaque nom de quickstart et chaque technologie dont il s'agit. Il y a une brève description pour chaque quickstart et une indication du niveau d'expérience requis pour l'installer. Pour des informations plus détaillées, cliquez sur le nom du quickstart.Certains quickstarts sont conçus pour améliorer ou étendre d'autres quickstarts. Ils sont indiqués dans la colonneConditions préalables
. Si un quickstart est associé à une liste de conditions préalables, vous devrez les installer avant d'utiliser le quickstart.Certains quickstart ont besoin de l'installation et de la configuraiton des composants optionnels. Ne pas installer ces composants à moins que le quickstart ne l'exige. - Exécuter le quickstart
helloworld
Le quickstarthelloworld
est l'un des quickstarts les plus simples, et représente un bon moyen de vérifier si le serveur JBoss est configuré et exécute correctement. Ouvrir le fichierREADME.html
dans la racine du quickstarthelloworld
. Il contient des instructions détaillés sur la façon de construire et de déployer le quickstart et accéder à l'application en cours. - Exécuter d'autres quickstarts.Suivre les instructions dans le fichier
README.html
que se trouve dans le dossier racine de chaque quickstart pour exécuter l'exemple.
1.4.3. Revoir les tutoriels Quickstart
1.4.3.1. Découvrir le Quickstart HelloWorld
Le Quickstart helloworld vous montre comment déployer un simple Servlet dans la plateforme JBoss EAP 6. La logique commerciale comprend un service fourni sous forme de bean CDI (Contexts and Dependency Injection) qui est injecté dans le Servlet. Ce Quickstart est très simple. Tout ce qu'il se contente de faire est d'imprimer "Hello World" dans une page web. C'est une bonne façon de savoir si vous avez bien configuré et démarré votre serveur.
helloworld
.
- Installer Red Hat JBoss Developer Studio en suivant la procédure qui suit : Section 1.3.1.3, « Installer Red Hat JBoss Developer Studio 7.1 ».
- Configurer Maven pour qu'il puisse être utilisé avec Red Hat JBoss Developer Studio en suivant la procédure qui suit : Section 2.3.3, « Configurer Maven pour utilisation dans Red Hat JBoss Developer Studio ».
- Suivre les procédures suivantes pour importer, créer et déployer le Quickstart
helloworld
dans Red Hat JBoss Developer Studio : Section 1.4.2.1, « Exécuter les quickstarts (démarrages rapides) dans Red Hat JBoss Developer Studio » - Vérifier que le Quickstart
helloworld
est déployé correctement dans JBoss EAP en ouvrant un navigateur web, et en accédant à l'application dans cet URL : http://localhost:8080/jboss-helloworld
Procédure 1.8. Observer la structure du répertoire
QUICKSTART_HOME/helloworld
. Le Quickstart helloworld comprend un Servlet et un bean CDI. Il comprend également un fichier beans.xml qui indique à JBoss EAP 6 comment trouver des beans pour cette application et comment activer le CDI.
- Le fichier
beans.xml
se trouve dans le dossierWEB-INF/
qui se trouve dans le répertoiresrc/main/webapp/
du Quickstart. - Le répertoire
src/main/webapp/
inclut également un fichierindex.html
qui utilise une simple réactualisation meta pour rediriger le navigateur de l'utilisateur vers le Servlet, qui se trouve à http://localhost:8080/jboss-helloworld/HelloWorld. - Tous les fichiers de configuration de cet exemple se trouvent dans
WEB-INF/
, qui se trouve dans le répertoiresrc/main/webapp/
de l'exemple. - Notez que le Quickstart n'a pas même besoin d'un fichier
web.xml
!
Procédure 1.9. Examiner le code
Vérifier le code HelloWorldServlet
Le fichierHelloWorldServlet.java
se trouve dans le répertoiresrc/main/java/org/jboss/as/quickstarts/helloworld/
. Le Servlet envoie les informations dans le navigateur.42. @SuppressWarnings("serial") 43. @WebServlet("/HelloWorld") 44. public class HelloWorldServlet extends HttpServlet { 45. 46. static String PAGE_HEADER = "<html><head><title>helloworld</title></head><body>"; 47. 48. static String PAGE_FOOTER = "</body></html>"; 49. 50. @Inject 51. HelloService helloService; 52. 53. @Override 54. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 55. resp.setContentType("text/html"); 56. PrintWriter writer = resp.getWriter(); 57. writer.println(PAGE_HEADER); 58. writer.println("<h1>" + helloService.createHelloMessage("World") + "</h1>"); 59. writer.println(PAGE_FOOTER); 60. writer.close(); 61. } 62. 63. }
Tableau 1.1. Infos HelloWorldServlet
Ligne Note 43 Avant Java EE 6, on utilisait un fichier XML pour enregistrer les Servlets. C'est bien plus clean. Tout ce qu'il vous reste à faire est d'ajouter l'annotation @WebServlet
et de fournir un mappage vers un URL qui est utilisé pour accéder au serveur.46-48 Chaque page web a besoin d'HTML formé correctement. Ce Quickstart utilise les Strings statiques pour écrire les sorties minimum de l'en-tête et du pied de page. 50-51 Ces lignes injectent le bean CDI HelloService, qui génère le message réel. Tant que nous ne changeons les API de HelloService, cette approche nous permet de modifier l'implémentation de HelloService à une date ultérieure sans changer l'affichage. 58 Cette ligne appelle le service pour générer le message "Hello World", et l'écrire dans la requête HTTP. Vérifier le code HelloService
Le fichierHelloService.java
se trouve dans le répertoiresrc/main/java/org/jboss/as/quickstarts/helloworld/
. Ce service est très simple. Il renvoie un message. Nul besoin d'enregistrement d'annotation ou d'XML.public class HelloService { String createHelloMessage(String name) { return "Hello " + name + "!"; } }
1.4.3.2. Découvrir le Quickstart numberguess
Ce Quickstart vous montre comment créer et déployer une simple application de JBoss EAP 6. Cette application ne persiste pas n'importe quelle information. Les informations sont affichées par JSF, et la logique métier est encapsulée dans deux beans CDI. Dans le Quickstart numberguess, vous obtenez 10 tentatives pour deviner un nombre entre 1 et 100. Après chaque tentative, on vous indique si votre estimation est trop élevée ou trop faible.
QUICKSTART_HOME/numberguess
. Le Quickstart hnumberguess comprend un certain nombre de beans, des fichiers de configuration et des affichages Facelets (JSF), tout cela dans un package de module WAR.
numberguess
.
- Installer Red Hat JBoss Developer Studio en suivant la procédure qui suit : Section 1.3.1.3, « Installer Red Hat JBoss Developer Studio 7.1 ».
- Configurer Maven pour qu'il puisse être utilisé avec Red Hat JBoss Developer Studio en suivant la procédure qui suit : Section 2.3.3, « Configurer Maven pour utilisation dans Red Hat JBoss Developer Studio ».
- Suivre les procédures suivantes pour importer, créer et déployer le Quickstart
numberguess
dans Red Hat JBoss Developer Studio : Section 1.4.2.1, « Exécuter les quickstarts (démarrages rapides) dans Red Hat JBoss Developer Studio » - Vérifier que le Quickstart
numberguess
est déployé correctement dans JBoss EAP en ouvrant un navigateur web, et en accédant à l'application dans cet URL : http://localhost:8080/jboss-numberguess
Procédure 1.10. Examiner les fichiers de configuration
WEB-INF/
, qui se trouve dans le répertoire src/main/webapp/
du Quickstart.
- Examiner le fichier
faces-config.xml
.Ce Quickstart utilise la version de JSF 2.0 defaces-config.xml
. Une version normalisée de Facelets correspond au gestionnaire d'affichage par défaut de JSF 2.0, donc il n'y a pas vraiment grand chose à configurer. JBoss EAP 6 va au-delà de Java EE ici. Il va automatiquement configurer JSF pour vous, si vous incluez ce fichier de configuration. En conséquence, la configuration ne consistera uniquement en l'élément racine :19. <faces-config version="2.0" 20. xmlns="http://java.sun.com/xml/ns/javaee" 21. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 22. xsi:schemaLocation=" 23. http://java.sun.com/xml/ns/javaee> 24. http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"> 25. 26. </faces-config>
- Examiner le fichier
beans.xml
.Il y a également un fichierbeans.xml
qui indique à JBoss EAP 6 de chercher des beans dans cette application et d'activer le CDI. - Il n'y a pas de fichier
web.xml
Notez que le Quickstart n'a pas même besoin d'un fichierweb.xml
!
Procédure 1.11. Examiner le code JSF
.xhtml
pour les fichiers source, mais s'occupe des vues rendues par l'extension .jsf
.
- Examiner le code
home.xhtml
.Le fichierhome.xhtml
se trouve dans le répertoiresrc/main/webapp/
.19. <html xmlns="http://www.w3.org/1999/xhtml" 20. xmlns:ui="http://java.sun.com/jsf/facelets" 21. xmlns:h="http://java.sun.com/jsf/html" 22. xmlns:f="http://java.sun.com/jsf/core"> 23. 24. <head> 25. <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> 26. <title>Numberguess</title> 27. </head> 28. 29. <body> 30. <div id="content"> 31. <h1>Guess a number...</h1> 32. <h:form id="numberGuess"> 33. 34. <!-- Feedback for the user on their guess --> 35. <div style="color: red"> 36. <h:messages id="messages" globalOnly="false" /> 37. <h:outputText id="Higher" value="Higher!" 38. rendered="#{game.number gt game.guess and game.guess ne 0}" /> 39. <h:outputText id="Lower" value="Lower!" 40. rendered="#{game.number lt game.guess and game.guess ne 0}" /> 41. </div> 42. 43. <!-- Instructions for the user --> 44. <div> 45. I'm thinking of a number between <span 46. id="numberGuess:smallest">#{game.smallest}</span> and <span 47. id="numberGuess:biggest">#{game.biggest}</span>. You have 48. #{game.remainingGuesses} guesses remaining. 49. </div> 50. 51. <!-- Input box for the users guess, plus a button to submit, and reset --> 52. <!-- These are bound using EL to our CDI beans --> 53. <div> 54. Your guess: 55. <h:inputText id="inputGuess" value="#{game.guess}" 56. required="true" size="3" 57. disabled="#{game.number eq game.guess}" 58. validator="#{game.validateNumberRange}" /> 59. <h:commandButton id="guessButton" value="Guess" 60. action="#{game.check}" 61. disabled="#{game.number eq game.guess}" /> 62. </div> 63. <div> 64. <h:commandButton id="restartButton" value="Reset" 65. action="#{game.reset}" immediate="true" /> 66. </div> 67. </h:form> 68. 69. </div> 70. 71. <br style="clear: both" /> 72. 73. </body> 74. </html>
Tableau 1.2. Infos JSF
Ligne Note 36-40 Voici les messages qui peuvent être envoyés par l'utilisateur : "Higher!" et "Lower!" 45-48 Au fur et à mesure que l'utilisateur devine, l'étendue des nombres qu'ils devinent se rétrécit. Cette phrase change pour s'assurer qu'ils connaissent la portée d'une tentative valide. 55-58 Ce champ d'entrée est lié à une propriété de bean qui utilise une expression de valeur. 58 On utilise une liaison de validateur pour s'assurer que l'utilisateur ne mette pas le nombre qu'il devine en dehors de la limite. Si le validateur n'était pas présent, l'utilisateur peut deviner un nombre en dehors de la limite. 59-61 Il doit y avoir un moyen pour que l'utilisateur envoie le nombre qu'il devine au serveur. Ici, on associe une méthode d'action sur le bean.
Procédure 1.12. Examiner les fichiers de classe
src/main/java/org/jboss/as/quickstarts/numberguess/
. La déclaration de paquet et les importations ont été exclues de ces listings. La liste complète se trouve dans le code source du Quickstart.
- Vérifier le code du qualificateur
Random.java
.Un qualificateur est utilisé pour supprimer l'ambiguïté entre deux beans, qui sont tous deux admissibles pour l'injection selon leur type. Pour plus d'informations sur les qualificateurs, se référer à Section 10.2.3.3, « Utiliser un qualificateur pour résoudre une injection ambiguë »Le qualificateur@Random
est utilisé pour injecter un nombre au hasard.@Target({ TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface Random { }
- Vérifier le code du qualificateur
MaxNumber.java
.Lequalificateur
@MaxNumber
est utilisé pour injecter le nombre maximum autorisé.@Target({ TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface MaxNumber { }
- Vérifier le code
Generator.java
.La classeGenerator
est chargé de créer le nombre aléatoire par une méthode de producteur. Elle indique également le nombre maximum possible par une méthode de producteur. Cette classe reste dans la portée de l'application (scoped), donc, vous n'obtenez pas un nombre différent au hasard à chaque fois.@SuppressWarnings("serial") @ApplicationScoped public class Generator implements Serializable { private java.util.Random random = new java.util.Random(System.currentTimeMillis()); private int maxNumber = 100; java.util.Random getRandom() { return random; } @Produces @Random int next() { // a number between 1 and 100 return getRandom().nextInt(maxNumber - 1) + 1; } @Produces @MaxNumber int getMaxNumber() { return maxNumber; } }
- Vérifier le code
Game.java
.La classe session scopedGame
est le point d'entrée principal de l'application. Elle est là pour initialiser et réinitialiser le jeu, pour capturer et valider la tentative de numéro de l'utilisateur, et afin de fournir un commentaire de retour à l'utilisateur avec unFacesMessage
. Elle utilise une méthode de cycle de vie de post-construction pour initialiser le jeu, en tirant un nombre au hasard du bean@Random Instance
<Integer>
.Notez l'annotation @Named dans la classe. Cette annotation est uniquement requise quand on veut rendre le bean accessible à une vue JSF via Expression Language (EL), et dans ce cas#{game}
.@SuppressWarnings("serial") @Named @SessionScoped public class Game implements Serializable { /** * The number that the user needs to guess */ private int number; /** * The users latest guess */ private int guess; /** * The smallest number guessed so far (so we can track the valid guess range). */ private int smallest; /** * The largest number guessed so far */ private int biggest; /** * The number of guesses remaining */ private int remainingGuesses; /** * The maximum number we should ask them to guess */ @Inject @MaxNumber private int maxNumber; /** * The random number to guess */ @Inject @Random Instance<Integer> randomNumber; public Game() { } public int getNumber() { return number; } public int getGuess() { return guess; } public void setGuess(int guess) { this.guess = guess; } public int getSmallest() { return smallest; } public int getBiggest() { return biggest; } public int getRemainingGuesses() { return remainingGuesses; } /** * Check whether the current guess is correct, and update the biggest/smallest guesses as needed. Give feedback to the user * if they are correct. */ public void check() { if (guess > number) { biggest = guess - 1; } else if (guess < number) { smallest = guess + 1; } else if (guess == number) { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!")); } remainingGuesses--; } /** * Reset the game, by putting all values back to their defaults, and getting a new random number. We also call this method * when the user starts playing for the first time using {@linkplain PostConstruct @PostConstruct} to set the initial * values. */ @PostConstruct public void reset() { this.smallest = 0; this.guess = 0; this.remainingGuesses = 10; this.biggest = maxNumber; this.number = randomNumber.get(); } /** * A JSF validation method which checks whether the guess is valid. It might not be valid because there are no guesses left, * or because the guess is not in range. * */ public void validateNumberRange(FacesContext context, UIComponent toValidate, Object value) { if (remainingGuesses <= 0) { FacesMessage message = new FacesMessage("No guesses left!"); context.addMessage(toValidate.getClientId(context), message); ((UIInput) toValidate).setValid(false); return; } int input = (Integer) value; if (input < smallest || input > biggest) { ((UIInput) toValidate).setValid(false); FacesMessage message = new FacesMessage("Invalid guess"); context.addMessage(toValidate.getClientId(context), message); } } }
1.4.4. Remplacer l'application web Welcome par défaut
Procédure 1.13. Remplacer l'application web Welcome par défaut par votre propre application web
Désactiver l'application Welcome
Utiliser le script d'interface CLIEAP_HOME/bin/jboss-cli.sh
pour exécuter la commande suivante. Vous aurez sans doute besoin de modifier un profil de domaine géré, ou retirer une portion de la commande/profile=default
du serveur autonome./profile=default/subsystem=web/virtual-server=default-host:write-attribute(name=enable-welcome-root,value=false)
Configurer votre application web par le contexte root.
Afin de configurer votre application web, pour qu'elle utilise (/) comme adresse URL, modifier son fichierjboss-web.xml
, qui se trouve dans le répertoireMETA-INF/
ouWEB-INF/
. Remplacer sa directive<context-root>
par une autre directive qui ressemble à ce qui suit.<jboss-web> <context-root>/</context-root> </jboss-web>
Déployer votre application.
Déployer votre application pour le groupe de serveurs ou le serveur que vous avez modifié lors de la première étape. L'application est maintenant disponible surhttp://SERVER_URL:PORT/
.
Chapitre 2. Guide Maven
2.1. Pour en savoir plus sur Maven
2.1.1. Le référentiel Maven
http://
pour les référentiels qui se trouvent sur un serveur HHTP ou file://
pour les référentiels qui se trouvent dans un serveur de fichiers.
2.1.2. Le fichier POM Maven
pom.xml
requiert certaines options de configuration définissant la valeur par défaut. Voir Section 2.1.3, « Conditions minimum pour un fichier POM Maven » pour plus de détails.
pom.xml
est disponible sur le lien http://maven.apache.org/maven-v4_0_0.xsd.
2.1.3. Conditions minimum pour un fichier POM Maven
Les conditions minimum pour un fichier pom.xml
sont les suivantes :
- project root
- modelVersion
- groupId - l'id du groupe du projet
- artifactId - l'id de l'artifact (projet)
- version - la version de l'artifact dans le groupe spécifié
Un fichier pom.xml
de base devrait resssembler à ceci :
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.jboss.app</groupId> <artifactId>my-app</artifactId> <version>1</version> </project>
2.1.4. Le fichier des configurations de Maven
settings.xml
contient des informations de configuration spécifiques à l'utilisateur pour Maven. Il contient des informations qui ne devraient pas être distribuées dans le fichier pom.xml
, comme l'identité du dévelopeur, l'information sur le proxy, l'emplacement du référentiel local, et autres paramètres propres à un utilisateur.
settings.xml
.
- Dans l'installation Maven
- Le fichier de configuration se trouve dans le répertoire
M2_HOME/conf/
. On les appelle les paramètresglobaux
. Le fichier de configuration Maven par défaut est un modèle qui peut être copié et utilisé comme point de départ pour le fichier des paramètres utilisateur. - Dans l'installation de l'utilisateur
- Le fichier de configuration se trouve dans le répertoire
USER_HOME/.m2/
. Si les fichierssettings.xml
et Maven existent tous les deux, leurs contenus seront fusionnés. S'il y a une intersection, le fichier utilisateursettings.xml
aura priorité.
settings.xml
Maven :
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <profiles> <!-- Configure the JBoss EAP Maven repository --> <profile> <id>jboss-eap-maven-repository</id> <repositories> <repository> <id>jboss-eap</id> <url>file:///path/to/repo/jboss-eap-6.3-maven-repository</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss-eap-maven-plugin-repository</id> <url>file:///path/to/repo/jboss-eap-6.3-maven-repository</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> </profiles> <activeProfiles> <!-- Optionally, make the repository active by default --> <activeProfile>jboss-eap-maven-repository</activeProfile> </activeProfiles> </settings>
settings.xml
à l'adresse suivante http://maven.apache.org/xsd/settings-1.0.0.xsd.
2.2. Installer le référentiel JBoss Maven et Maven
2.2.1. Télécharger et installer Maven
- Aller dans Apache Maven Project - Download Maven et télécharger la dernière distribution de votre système d'exploitation.
- Voir la documentation Maven pour les informations sur le façon de télécharger et d'installer Apache Maven sur votre système d'exploitation.
2.2.2. Installer le référentiel Maven de JBoss EAP 6
2.2.3. Installer le référentiel Maven de JBoss EAP 6 localement
Le référentiel de JBoss EAP 6.3 Maven est disponible en ligne. Il n'est pas donc nécessaire de le télécharger et de l'installer localement. Toutefois, si vous préférez installer le référentiel JBoss EAP Maven localement, il y a trois façons de procéder : sur votre système de fichiers local, sur le serveur Web Apache, ou avec un gestionnaire de référentiel Maven. Cet exemple couvre les étapes pour télécharger le référentiel JBoss EAP 6 Maven sur le système de fichiers local. Cette option est facile à configurer et vous permet d'obtenir d'être opérationnel rapidement sur votre ordinateur local. Il peut vous aider à vous familiariser à l'utilisation de Maven pour le développement, mais n'est pas recommandé pour les environnements de production en équipes.
Procédure 2.1. Télécharger et installer le référentiel Maven de JBoss EAP 6 sur le système de fichier local.
- Ouvrir un navigateur web, et accéder à cet URL: https://access.redhat.com/jbossnetwork/restricted/listSoftware.html?product=appplatform.
- Chercher "Red Hat JBoss Enterprise Application Platform 6.3.0 Maven Repository" dans la liste.
- Cliquer sur le bouton Télécharger pour télécharger un fichier
.zip
contenant le référentiel. - Décompresser le fichier dans le même répertoire sur votre système de fichiers local dans un répertoire de votre choix.
Ceci crée un répertoire de référentiel Maven appelé jboss-eap-6.3.0.GA-maven-repository
.
Important
settings.xml
de Maven. Chaque référentiel local doit être configuré dans sa propre balise <repository>
.
Important
repository/
cache, qui se situe sous le répertoire .m2/
avant de tenter d'utiliser le nouveau répertoire Maven.
2.2.4. Installer le référentiel Maven de JBoss EAP 6 à utiliser avec Appache httpd
Il vous faut configurer Apache httpd. Voir la documentation Apache HTTP Server Project pour obtenir des instructions.
Procédure 2.2. Télécharger l'archive ZIP du référentiel Maven de JBoss EAP 6
- Ouvrir un navigateur web, et accéder à cet URL : https://access.redhat.com/jbossnetwork/restricted/listSoftware.html?product=appplatform.
- Chercher "Red Hat JBoss Enterprise Application Platform 6.3.0 Maven Repository" dans la liste.
- Cliquer sur le bouton Télécharger pour télécharger un fichier
.zip
contenant le référentiel. - Décompresser les fichiers dans un répertoire qui soit accessible au serveur Apache.
- Configurer Apache pour lui donner la permission écriture et pour permettre la navigation dans le répertoire créé.
Cela permet à un environnement multi-utilisateurs d'accéder à un référentiel Maven sur Apache httpd.
Note
2.2.5. Installer le référentiel Maven de JBoss EAP 6 en utilisant le gestionnaire de référentiels Nexus Maven
Procédure 2.3. Télécharger l'archive ZIP du référentiel Maven de JBoss EAP 6
- Ouvrir un navigateur web, et accéder à cet URL : https://access.redhat.com/jbossnetwork/restricted/listSoftware.html?product=appplatform.
- Chercher "Red Hat JBoss Enterprise Application Platform 6.3.0 Maven Repository" dans la liste.
- Cliquer sur le bouton Télécharger pour télécharger un fichier
.zip
contenant le référentiel. - Décompresser les fichiers dans un répertoire de votre choix sur le serveur qui héberge Nexus.
Procédure 2.4. Ajouter le référentiel Maven de JBoss EAP 6 en utilisant le gestionnaire de référentiels Nexus Maven
- Connectez-vous à Nexus en tant qu'administrateur.
- Sélectionner la section Repositories à partir du menu Views → Repositories qui se trouve à gauche du gestionnaire de référentiels.
- Cliquer sur le menu déroulant Add..., puis sélectionner Hosted Repository.
- Donner un nom et une ID au nouveau référentiel.
- Saisir le chemin du disque qui mène au référentiel décompressé dans le champ d'emplacement Override Local Storage.
- Continuer si vous souhaitez que l'artéfact soit disponible dans un groupe de référentiels. Ne pas continuer avec cette procédure si ce n'est pas ce que vous souhaitez.
- Sélectionner le groupe de référentiels.
- Cliquer sur l'onglet Configure.
- Déplacez le nouveau référentiel JBoss Maven de la liste Available Repositories vers la liste Ordered Group Repositories sur la gauche.
Note
Notez que l'ordre de cette liste détermine la priorité de recherche d'artefacts Maven.
Le référentiel est configuré par le gestionnaire de référentiels Maven Nexus.
2.2.6. Gestionnaires de référentiels Maven
- Ils donnent la possibilité de configurer des proxys entre votre organisation et des référentiels Maven à distance, ce qui offre un grand nombre d'avantages, parmi lesquels des déploiements plus rapides et plus efficaces et un meilleur niveau de contrôle sur ce qui est téléchargé par Maven.
- Ils fournissent des destinations de déploiement pour les artefacts que vous aurez vous-même générés, permettant ainsi une collaboration entre différentes équipes de développement au sein d'une organisation.
Gestionnaires de référentiels Maven les plus communément utilisés
- Sonatype Nexus
- Voir Sonatype Nexus: Manage Artifacts pour obtenir plus d'informations sur Nexus.
- Artifactory
- Voir Artifactory Open Source pour obtenir plus d'informations sur Artifactory.
- Apache Archiva
- Voir Apache Archiva: The Build Artifact Repository Manager pour obtenir plus d'informations sur Apache Archiva.
2.3. Utiliser le référentiel Maven
2.3.1. Configurer le référentiel Maven 6 de JBoss EAP
Il existe deux approches pour amener Maven à utiliser le référentiel Maven de JBoss EAP 6 dans votre projet :
- Vous pouvez configurer les référentiels dans les paramètres globaux ou d'utilisateur de Maven.
- Vous pouvez configurer les référentiels dans le fichier POM du projet.
Procédure 2.5. Configurer les paramètres Maven pour qu'ils utilisent le référentiel Maven de JBoss EAP 6
Configurer le référentiel Maven par les paramètres Maven
Nous vous conseillons cette dernière approche. Les paramètres Maven utilisés avec un gestionnaire de référentiel ou un référentiel sur un serveur partagé offrent un meilleur contrôle et une meilleure gestion des projets. Les paramètres offrent également la capacité d'utiliser un miroir alternatif pour rediriger toutes les demandes de recherche pour un référentiel spécifique vers un gestionnaire de référentiel sans changer les fichiers du projet. Pour plus d'informations concernant les miroirs, veuillez consulter http://maven.apache.org/guides/mini/guide-mirror-settings.html.Cette méthode de configuration s'applique à tous les projets Maven, tant que le fichier POM du projet ne contient pas de configuration de référentiel.Configurer le référentiel Maven pour qu'il utilise le fichier POM du projet.
Cette méthode de configuration est généralement déconseillée. Si vous décidez de configurer des référentiels dans le fichier POM de votre projet, planifiez de manière prudente et souvenez-vous que cela pourrait ralentir votre build et que vous pourriez vous retrouver avec des artefacts ne provenant pas du référentiel attendu.Note
Dans le cas d'une entreprise, où un gestionnaire de référentiel est généralement utilisé, Maven doit interroger tous les artefacts pour tous les projets en utilisant ce gestionnaire. Maven utilise tous les référentiels déclarés pour trouver les artéfacts manquants. Par conséquent, s'il ne peut trouver ce qu'il cherche, il pourra le chercher dans la centrale de référentiels (définie dans le fichier POM parent intégré). Pour remplacer cet emplacement central, vous pouvez ajouter une définition aveccentral
de manière à ce que la centrale de référentiels devienne également votre gestionnaire de référentiel. Cela fonctionne bien avec les projets établis, mais pose un problème pour les projets vierges ou récents puisque cela crée une dépendance cyclique.Les fichiers POM inclus de manière transitive représentent également un problème avec ce type de configuration. Maven doit interroger ces référentiels externes pour trouver les artefacts manquants. Non seulement cela ralentira votre build, mais vous fera également perdre le contrôle sur la provenance de vos artefacts et risquera d'endommager votre build.Cette méthode de configuration remplace les configuration utilisateur et globales pour le projet configuré.
2.3.2. Configurer le référentiel JBoss EAP 6 Platform Maven Repository par les paramètres de configuration de Maven
- Vous pouvez modifier les paramètres Maven. Cela amène Maven à utiliser la configuration à travers tous les projets.
- Vous pouvez configurer le fichier POM du projet. Cela limite la configuration au projet particulier.
Note
- Système de fichiers
- file:///path/to/repo/jboss-eap-6.x-maven-repository
- Apache Web Server
- http://intranet.acme.com/jboss-eap-6.x-maven-repository/
- Gestionnaire de référentiel Nexus
- https://intranet.acme.com/nexus/content/repositories/jboss-eap-6.x-maven-repository
Procédure 2.6. Configurer Maven par les paramètres fournis dans les exemples Quickstart
settings.xml
configuré pour utiliser le référentiel JBoss EAP 6 Maven en ligne. Il s'agit de l'approche la plus simple.
- Cette procédure remplace le fichier de configuration Maven existant, donc vous devrez sauvegarder le fichier
settings.xml
Maven existant.- Chercher le répertoire d'installation Maven qui corresponde à votre système d'exploitation. Il se trouve normalement dans le répertoire
USER_HOME/.m2/
.- Dans Linux ou Mac, c'est:
~/.m2/
- Pour Windows, c'est :
\Documents and Settings\USER_NAME\.m2\
ou\Users\USER_NAME\.m2\
- Si vous avez un fichier
USER_HOME/.m2/settings.xml
existant, renommer le et faire une copie de sauvegarde afin de pouvoir le restaurer plus tard.
- Télécharger et décompresser les exemples quickstart fournis dans JBoss EAP 6. Pour plus d'informations, voir Section 1.4.1.1, « Accès aux Quickstarts »
- Copier le fichier
QUICKSTART_HOME/settings.xml
dans le répertoireUSER_HOME/.m2/
. - Si vous modifiez le fichier
settings.xml
tandis que Red Hat JBoss Developer Studio est en cours d'exécution, suivre la procédure ci-dessous intitulée Refresh the JBoss Developer Studio User Settings.
Procédure 2.7. Modifier et configurer les paramètres Maven manuellement pour qu'ils utilisent le référentiel Maven de JBoss EAP 6 en ligne
- Chercher le répertoire d'installation Maven qui corresponde à votre système d'exploitation. Il se trouve normalement dans le répertoire
USER_HOME/.m2/
.- Dans Linux ou Mac, c'est
~/.m2/
- Pour Windows, c'est
\Documents and Settings\USER_NAME\.m2\
ou\Users\USER_NAME\.m2\
- Si vous ne trouvez pas de fichier
settings.xml
, copier le fichiersettings.xml
du répertoireUSER_HOME/.m2/conf/
dans le répertoireUSER_HOME/.m2/
. - Copier l'XML suivant dans l'élément
<profiles>
du fichier.<!-- Configure the JBoss GA Maven repository --> <profile> <id>jboss-ga-repository</id> <repositories> <repository> <id>jboss-ga-repository</id> <url>http://maven.repository.redhat.com/techpreview/all</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss-ga-plugin-repository</id> <url>http://maven.repository.redhat.com/techpreview/all</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> <!-- Configure the JBoss Early Access Maven repository --> <profile> <id>jboss-earlyaccess-repository</id> <repositories> <repository> <id>jboss-earlyaccess-repository</id> <url>http://maven.repository.redhat.com/earlyaccess/all/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss-earlyaccess-plugin-repository</id> <url>http://maven.repository.redhat.com/earlyaccess/all/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile>
Copier l'XML suivant dans l'élément<activeProfiles>
desettings.xml
.<activeProfile>jboss-ga-repository</activeProfile> <activeProfile>jboss-earlyaccess-repository</activeProfile>
- Si vous modifiez le fichier
settings.xml
tandis que Red Hat JBoss Developer Studio est en cours d'exécution, suivre la procédure ci-dessous intitulée Refresh the JBoss Developer Studio User Settings.
Procédure 2.8. Configurer les paramètres pour pouvoir utiliser un référentiel JBoss EAP installé localement
- Chercher le répertoire d'installation Maven qui corresponde à votre système d'exploitation. Il se trouve normalement dans le répertoire
USER_HOME/.m2/
.- Dans Linux ou Mac, c'est
~/.m2/
- Pour Windows, c'est
\Documents and Settings\USER_NAME\.m2\
ou\Users\USER_NAME\.m2\
- Si vous ne trouvez pas de fichier
settings.xml
, copier le fichiersettings.xml
du répertoireUSER_HOME/.m2/conf/
dans le répertoireUSER_HOME/.m2/
. - Copier l'XML suivant dans l'élément
<profiles>
du fichiersettings.xml
. Veillez bien à changer l'<url>
à l'emplacement de référentiel lui-même.<profile> <id>jboss-eap-repository</id> <repositories> <repository> <id>jboss-eap-repository</id> <name>JBoss EAP Maven Repository</name> <url>file:///path/to/repo/jboss-eap-6.x-maven-repository</url> <layout>default</layout> <releases> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </releases> <snapshots> <enabled>false</enabled> <updatePolicy>never</updatePolicy> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss-eap-repository-group</id> <name>JBoss EAP Maven Repository</name> <url> file:///path/to/repo/jboss-eap-6.x-maven-repository </url> <layout>default</layout> <releases> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </releases> <snapshots> <enabled>false</enabled> <updatePolicy>never</updatePolicy> </snapshots> </pluginRepository> </pluginRepositories> </profile>
Copier l'XML suivant dans l'élément<activeProfiles>
desettings.xml
.<activeProfile>jboss-eap-repository</activeProfile>
- Si vous modifiez le fichier
settings.xml
tandis que Red Hat JBoss Developer Studio est en cours d'exécution, suivre la procédure ci-dessous intitulée Refresh the JBoss Developer Studio User Settings.
Procédure 2.9. Réactualiser les paramètres de configuration d'utilisateur de Red Hat JBoss Developer Studio
settings.xml
tandis que Red Hat JBoss Developer Studio est en cours d'exécution, vous devrez réactualiser les paramètres de configuration d'utilisateur.
- À partir du menu, sélectionner Window → Preferences.
- Dans la fenêtre Window Preferences, étendre Maven et sélectionner User Settings.
- Cliquer sur le bouton Update Settings (Mise à jour Configuration) pour réactualiser les configurations utilisateur de Maven dans Red Hat JBoss Developer Studio.
Figure 2.1. Mise à jour des paramètres de configuration de l'utilisateur Maven
Important
- Missing artifact ARTIFACT_NAME
- [ERROR] Failed to execute goal on project PROJECT_NAME; Could not resolve dependencies for PROJECT_NAME
~/.m2/repository/
dans Linux, et dans le sous-répertoire %SystemDrive%\Users\USERNAME\.m2\repository\
dans Windows.
2.3.3. Configurer Maven pour utilisation dans Red Hat JBoss Developer Studio
Procédure 2.10. Configurer Maven dans Red Hat JBoss Developer Studio
- Cliquer sur Window→Preferences, puis JBoss Tools et sélectionner JBoss Maven Integration.
Figure 2.2. Panneau d'intégration de JBoss Maven dans la fenêtre Préférences
- Cliquer sur Configure Maven Repositories.
- Cliquer sur Add Repository pour configurer le référentiel de JBoss GA Tech Preview Maven. Remplir les champs de
Add Maven Repository
comme suit :- Définir les valeurs de Profile ID, Repository ID, et Repository Name à
jboss-ga-repository
. - Définir la valeur de Repository URL à
http://maven.repository.redhat.com/techpreview/all
. - Cliquer sur la case Active by default pour activer le référentiel Maven.
- Cliquer sur OK
Figure 2.3. Ajouter le référentiel Maven - JBoss Tech Preview
- Cliquer sur Add Repository pour configurer le référentiel JBoss Early Access Maven. Remplir les champs de
Add Maven Repository
comme suit :- Définir les valeurs de Profile ID, Repository ID, et Repository Name à
jboss-earlyaccess-repository
. - Définir la valeur de Repository URL à
http://maven.repository.redhat.com/techpreview/all
. - Cliquer sur la case Active by default pour activer le référentiel Maven.
- Cliquer sur OK
Figure 2.4. Ajouter le référentiel Maven - JBoss Early Access
- Vérifier les référentiels et cliquer sur Finish.
Figure 2.5. Vérifier les référentiels Maven
- Le message suivant appraîtra "Are you sure you want to update the file 'MAVEN_HOME/settings.xml'?". Cliquer sur Yes pour mettre les paramètres de configuration à jour. Cliquer sur OK pour fermer la boîte de dialogue.Le référentiel Maven est maintenant configuré pour utilisation dans Red Hat JBoss Developer Studio
2.3.4. Configurer le référentiel JBoss EAP 6 Platform Maven Repository par le Projet POM
- Vous pouvez modifier les paramètres Maven.
- Vous pouvez configurer le fichier POM du projet.
pom.xml
. Cette méthode de configuration remplace les configurations Utilisateur et Globales.
Note
central
de manière à ce que la centrale de référentiels devienne également votre gestionnaire de référentiel. Cela fonctionne bien avec les projets établis, mais pose un problème pour les projets vierges ou récents puisque cela crée une dépendance cyclique.
Note
- Système de fichiers
- file:///path/to/repo/jboss-eap-6.x-maven-repository
- Apache Web Server
- http://intranet.acme.com/jboss-eap-6.x-maven-repository/
- Gestionnaire de référentiel Nexus
- https://intranet.acme.com/nexus/content/repositories/jboss-eap-6.x-maven-repository
- Ouvrir le fichier
pom.xml
de votre projet dans un éditeur de texte. - Ajouter la configuration du référentiel suivant. S'il y a déjà une configuration
<repositories>
qui se trouve dans le fichier, lui ajouter l'élément<repository>
. Veillez bien à modifier l'<url>
pour qu'il corresponde bien à l'emplacement du référentiel.<repositories> <repository> <id>jboss-eap-repository-group</id> <name>JBoss EAP Maven Repository</name> <url>file:///path/to/repo/jboss-eap-6.3.0-maven-repository/</url> <layout>default</layout> <releases> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </releases> <snapshots> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </snapshots> </repository> </repositories>
- Ajouter la configuration de référentiel de plug-in suivante. S'il existe déjà une configuration
<pluginRepositories>
dans le fichier, lui ajouter l'élément<pluginRepository>
.<pluginRepositories> <pluginRepository> <id>jboss-eap-repository-group</id> <name>JBoss EAP Maven Repository</name> <url>file:///path/to/repo/jboss-eap-6.3.0-maven-repository/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories>
2.3.5. Gestion des dépendances du projet
pom.xml
(POM) qui indique les versions de toutes les dépendances d'exécution d'un module donné. Les dépendances de versions sont listées dans la section de gestion des dépendances du fichier.
groupId:artifactId:version
(GAV) à la section de gestion des dépendances du fichier pom.xml
du projet et en spécifiant <scope>import</scope>
et les valeurs de l'élément <type>pom</type>
.
Note
fourni
. C'est parce que ces classes sont fournies par le serveur d'applications en cours d'exécution et qu'il n'est pas nécessaire de les empaqueter avec l'application utilisateur.
Artéfacts Maven pris en charge
-redhat
, par exemple 1.0.0-redhat-1
.
pom.xml
de configuration de build garantit que le build utilise l'artefact binaire correct pour la génération de builds locaux et pour le testing. Notez qu'un artefact avec une version -redhat
ne fait pas nécessairement partie de l'API public prise en charge et peut changer à l'avenir au cours des révisions. Pour plus d'informations sur l'API public pris en charge, voir la documentation JavaDoc incluse dans la sortie.
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifact> <version>4.2.6.Final-redhat-1</version> <scope>provided</scope> </dependency>Notez que l'exemple ci-dessus contient une valeur pour le champ
<version/>
. Cependant, il est recommandé d'utiliser la gestion des dépendances Maven pour configurer les versions de dépendances.
Gestion des dépendances
<dependencyManagement> <dependencies> ... <dependency> <groupId>org.jboss.bom</groupId> <artifactId>eap6-supported-artifacts</artifactId> <version>6.3.0.GA</version> <type>pom</type> <scope>import</scope> </dependency> ... </dependencies> </dependencyManagement>
JBoss JavaEE Specs Bom de nomenclature
jboss-javaee-6.0
contient les JAR de spécification JAVA EE utilisés dans JBoss EAP.
3.0.2.Final-redhat-x
de la NOMENCL jboss-javaee-6.0
.
<dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>3.0.2.Final-redhat-x</version> <type>pom</type> <scope>import</scope> </dependency> ... </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.spec.javax.servlet</groupId> <artifactId>jboss-servlet-api_3.0_spec</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.spec.javax.servlet.jsp</groupId> <artifactId>jboss-jsp-api_2.2_spec</artifactId> <scope>provided</scope> </dependency> ... </dependencies>
Les nomenclatures JBoss EAP BOM et les Quickstarts
Tableau 2.1. Nomenclatures JBoss BOM utilisées par les Quickstarts
Id Artéfact Maven | Description |
---|---|
jboss-javaee-6.0-with-hibernate | Cette nomenclature BOM s'appuie sur le profil BOM complet de Java EE, ajoutant des projets communautaires Hibernate ORM, Hibernate Search et Hibernate Validator. Elle fournit également des projets d'outil tel que Hibernate JPA Model Gen et le processeur Hibernate Validator Annotation. |
jboss-javaee-6.0-with-hibernate3 | Cette nomenclature BOM s'appuie sur le profil BOM complet de Java EE, ajoutant des projets communautaires Hibernate 3 ORM, Hibernate Entity Manager (JPA 1.0) et Hibernate Validator. |
jboss-javaee-6.0-with-logging | Cette nomenclature BOM s'appuie sur le profil BOM complet de Java EE, ajoutant JBoss Logging Tools et Log4j framework. |
jboss-javaee-6.0-with-osgi | Cette nomenclature BOM s'appuie sur le profil BOM complet de Java EE, ajoutant OSGI. |
jboss-javaee-6.0-with-resteasy | Cette nomenclature BOM s'appuie sur le profil BOM complet de Java EE, ajoutant RESTEasy |
jboss-javaee-6.0-with-security | Cette nomenclature BOM s'appuie sur le profil BOM complet de Java EE, ajoutant Picketlink. |
jboss-javaee-6.0-with-tools | Cette nomenclature BOM s'appuie sur le profil BOM complet de Java EE, ajoutant Arquillian à l'ensemble. Elle procure également une version de JUnit et de TestNG conseillés pour l'utilisation avec Arquillian. |
jboss-javaee-6.0-with-transactions | Cette nomenclature BOM inclut un gestionnaire de transactions de classe mondiale. Utiliser les API JBossTS pour pouvoir profiter de toutes ses fonctionnalités. |
6.3.0.GA
de la nomemclature BOM jboss-javaee-6.0-with-hibernate
.
<dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.bom.eap</groupId> <artifactId>jboss-javaee-6.0-with-hibernate</artifactId> <version>6.3.0.GA</version> <type>pom</type> <scope>import</scope> </dependency> ... </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <scope>provided</scope> </dependency> ... </dependencies>
JBoss Client BOMs
jboss-as-ejb-client-bom
et jboss-as-jms-client-bom
.
7.4.0.Final-redhat-x
du client jboss-as-ejb-client-bom
BOM.
<dependencies> <dependency> <groupId>org.jboss.as</groupId> <artifactId>jboss-as-ejb-client-bom</artifactId> <version>7.4.0.Final-redhat-x</version> <type>pom</type> </dependency> ...l </dependencies>Cet exemple utilise la version
7.4.0.Final-redhat-x
du client BOM jboss-as-jms-client-bom
.
<dependencies> <dependency> <groupId>org.jboss.as</groupId> <artifactId>jboss-as-jms-client-bom</artifactId> <version>7.4.0.Final-redhat-x</version> <type>pom</type> </dependency> ... </dependencies>
2.4. Mise à niveau du référentiel Maven
2.4.1. Appliquer un correctif dans le répertoire Maven local
Un référentiel Maven stocke des bibliothèques Java, des plug-ins et autres objets nécessaires pour compiler et déployer des applications JBoss EAP. Le référentiel de JBoss EAP est disponible en ligne ou en fichier ZIP téléchargé. Si vous utilisez le référentiel hébergé publiquement, les mises à jour seront appliquées automatiquement. Toutefois, si vous téléchargez et installez le repository Maven localement, vous serez chargé d'appliquer les mises à jour vous-même. Chaque fois qu'un correctif sera disponible dans JBoss EAP, un correctif correspondant sera fourni pour le référentiel JBoss EAP Maven. Ce correctif est disponible sous la forme d'un fichier ZIP incrémentiel qui est décompressé dans le référentiel local existant. Le fichier ZIP contient des nouveaux fichiers JAR et POM. Il n'écrase pas les JAR existants, ni ne les supprime, donc il n'y a aucune exigence de restauration.
unzip
.
Conditions préalables
- Accès valide et abonnement au portail clients de Red Hat.
- Le fichier Red Hat JBoss Enterprise Application Platform 6.3.0 Maven Repository ZIP, téléchargé et installé localement.
Procédure 2.11. Mise à jour du référentiel Maven
- Ouvrir un navigateur et connectez-vous dans https://access.redhat.com.
- Sélectionner Téléchargements du menu en haut de la page.
- Cherchez
Red Hat JBoss Enterprise Application Platform
dans la liste et cliquez dessus. - Sélectionner la version de JBoss EAP qui convient à partir du menu déroulant Version qui apparaît sur l'écran, puis cliquer sur Patches.
- Chercher
Red Hat JBoss Enterprise Application Platform 6.3 CPx Incremental Maven Repository
dans la liste et cliquer sur Download. - Vous êtes invités à sauvegarder le fichier ZIP dans un répertoire de votre choix. Sélectionner un répertoire et sauvegardez le fichier.
- Chercher le chemin d'accès vers le répertoire JBoss EAP dont il s'agit dans les commandes ci-dessous, sous EAP_MAVEN_REPOSITORY_PATH, correspondant à votre système d'exploitation. Pour obtenir plus d'informations sur la façon d'installer le référentiel Maven sur le système de fichiers local, voir Section 2.2.3, « Installer le référentiel Maven de JBoss EAP 6 localement ».
- Décompresser le fichier de correctifs Maven dans le répertoire d'installation de JBoss EAP 6.3.x.
- Dans Linux, ouvrir un terminal et saisir la commande suivante :
[standalone@localhost:9999 /]
unzip -o jboss-eap-6.3.x-incremental-maven-repository.zip -d
EAP_MAVEN_REPOSITORY_PATH
- Dans Windows, utiliser l'utilitaire pour extraire le fichier ZIP pour le mettre dans la racine du répertoire
EAP_MAVEN_REPOSITORY_PATH
.
Le référentiel Maven installé localement est mis à jour au dernier correctif.
Chapitre 3. Chargement de classes modulaire et modules
3.1. Introduction
3.1.1. Chargement des classes de chargement et de modules
3.1.2. Chargement des classes
3.1.3. Modules
- Modules statiques
- Les modules statiques sont prédéfinis dans le répertoire
EAP_HOME/modules/
du serveur d'applications. Chaque sous-répertoire représente un module et contient un fichier de configuration (module.xml
) et tout fichier JAR requis. Le nom du module est défini dans le fichiermodule.xml
. Tous les API fournis par le serveur de l'application sont des modules statiques, y compris les API Java EE, et les autres API comme JBoss Logging.Exemple 3.1. Exemple de fichier module.xml
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.15.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
Le nom du module,com.mysql
, doit correspondre à la structure du répertoire du module.Les modules fournis dans les distributions JBoss EAP se trouvent dans un répertoiresystem
se trouvant lui-même dans le répertoireJBOSS_HOME/modules
. Cela les rend séparés de tout module fourni par une tierce partie.Tout produit mis en couche de Red Hat, se superposant sur JBoss EAP 6.1 ou version supérieure installera également leurs modules dans le répertoiresystem
.La création de modules statiques personnalisés peut être utile si plusieurs applications sont déployées sur un même serveur utilisant les mêmes bibliothèques de tierce partie. Au lieu d'un regroupement de ces bibliothèques pour chaque application, un module contenant ces bibliothèques peut être créé et installé par l'administrateur JBoss. Les applications peuvent ensuite déclarer une dépendance explicite sur les modules statiques personnalisés.Les utilisateurs doivent s'assurer que les modules personnalisés soient installés dans le répertoireJBOSS_HOME/modules
, en utilisant un répertoire par couche de modules. Cela garantit que les versions personnalisées de modules qui existent déjà dans le répertoiresystem
soient bien chargées à la place des versions fournies. Ainsi, les modules utilisateur auront la priorité sur les modules fournis par le système.Si vous utilisez la variable d'environnementJBOSS_MODULE_PATH
pour changer les emplacements où JBoss EAP cherche les modules, le produit ira chercher dans une structure de sous-répertoiresystem
dans un des emplacements spécifiés. Une structure de sous-répertoiresystem
doit exister quelquepart dans les emplacements spécifiés dansJBOSS_MODULE_PATH
. - Modules dynamiques
- Les modules dynamiques sont créés et chargés par le serveur d'application pour chaque déploiement JAR ou WAR (ou sous-déploiement d'un EAR). Le nom d'un module dynamique est dérivé du nom de l'archive déployée. Comme les déploiements sont chargés sous forme de modules, ils peuvent configurer des dépendances et peuvent être utilisés comme dépendances par d'autres déploiements.
3.1.4. Les dépendances de modules
Exemple 3.2. Les dépendances de module
- Le Module A déclare une dépendance explicite sur le Module C, ou bien
- Le Module B exporte ses dépendances sur le Module C.
3.1.5. Chargement des classes dans les déploiements
- Déploiement WAR
- Un déploiement WAR est un simple module. Les classes du répertoire
WEB-INF/lib
sont considérées de la même manière que celles du répertoireWEB-INF/classes
. Toutes les classes empaquetées dans le war seront téléchargées par le même chargeur de classes. - Déploiement EAR
- Les déploiements EAR sont faits de plus d'un module. La définition de ces modules suit ces règles :
- Le répertoire
lib/
du EAR est un simple module nommé le module parent. - Chaque déploiement WAR du EAR est un simple module.
- Chaque déploiement EJB JAR du EAR est un simple module.
Les modules de sous-déploiement (les déploiements WAR et JAR dans EAR) ont une dépendance automatique sur le module parent. Cependant ils n'ont pas de dépendance automatique l'un sur l'autre. Ceci est appelé l'isolement du sous-déploiement et peut être désactivé par déploiement ou pour le serveur de toute l'application dans son ensemble.Les dépendances explicites entre les modules de sous-déploiement peuvent être ajoutées par les mêmes moyens, tout comme pour tout autre module.
3.1.6. Précédence pour le chargement des classes
- Dépendances implicites.Voici les dépendances qui sont ajoutées automatiquement par JBoss EAP 6, comme les API JAVA EE. Ces dépendances ont la plus haute précédence de chargeur de classe car ils contiennent des API et des fonctionnalités communes qui sont fournies par JBoss EAP 6.Voir Section 3.8.1, « Dépendances de modules implicites » pour obtenir des détails sur chaque dépendance implicite.
- Dépendances explicitesIl s'agit de dépendances qui sont ajoutées manuellement dans la configuration de l'application. Cela peut être fait à l'aide du fichier d'application
MANIFEST.MF
ou du nouveau fichier du descripteur de déploiement en option de JBossjboss-deployment-structure.xml
.Voir Section 3.2, « Ajouter une dépendance de module explicite à un déploiement » pour apprendre comment ajouter des dépendances explicites. - Ressources locales.Fichiers de classe empaquetées à l'intérieur du déploiement lui-même, par ex. les répertoires
WEB-INF/classes
ouWEB-INF/lib
d'un fichier WAR. - Dépendances inter-déploiement.Ce sont des dépendances sur les autres déploiements d'un déploiement EAR. Cela peut inclure des classes du répertoire
lib
du EAR ou des classes des autres jars EJB.
3.1.7. Nommage de modules dynamiques
- Les déploiements des fichiers WAR et JAR sont nommés selon le format suivant :
deployment.DEPLOYMENT_NAME
Par exemple,inventory.war
etstore.jar
auront les mêmes noms de module quedeployment.inventory.war
etdeployment.store.jar
respectivement. - Les sous-déploiements des archives Enterprise sont nommés selon le format suivant :
deployment.EAR_NAME.SUBDEPLOYMENT_NAME
Ainsi, le sous-déploiementreports.war
, qui se trouve dans l'archive Enterpriseaccounts.ear
, aura le nom de module dudeployment.accounts.ear.reports.war
.
3.1.8. jboss-deployment-structure.xml
jboss-deployment-structure.xml
est un descripteur de déploiement optionnel de JBoss EAP 6. Ce descripteur de déploiement fournit un contrôle pour le chargement de classes dans le déploiement.
EAP_HOME/docs/schema/jboss-deployment-structure-1_2.xsd
3.2. Ajouter une dépendance de module explicite à un déploiement
Conditions préalables
- Vous devez déjà avoir un projet de logiciel qui fonctionne, et auquel vous souhaitez ajouter une dépendance de module.
- Vous devez connaître le nom du module qui est ajouté comme dépendance. Voir Section 3.8.2, « Les modules inclus » pour obtenir la liste des modules statiques inclus dans JBoss EAP 6. Si le module correspond à un autre déploiement, voir Section 3.1.7, « Nommage de modules dynamiques » pour déterminer le nom du module.
- Par l'ajout d'entrées dans le fichier
MANIFEST.MF
du déploiement. - Par l'ajout d'entrées dans le descripteur de déploiement
jboss-deployment-structure.xml
.
Procédure 3.1. Par l'ajout d'une configuration de dépendance à MANIFEST.MF
MANIFEST.MF
. Voir Section 3.3, « Générer des entrées MANIFEST.MF en utilisant Maven ».
Ajouter le fichier
MANIFEST.MF
Si le projet ne possède pas de fichierMANIFEST.MF
, créer un fichier nomméMANIFEST.MF
. Pour une application web (WAR), ajouter ce fichier au répertoireMETA-INF
. Pour une archive EJB (JAR), l'ajouter au répertoireMETA-INF
.Ajouter une entrée de dépendance
Ajouter une entrée de dépendance au fichierMANIFEST.MF
avec une liste de noms de modules de dépendance séparés par des virgules.Dépendances : org.javassist, org.apache.velocity
Option : rendre une dépendance optionnelle
On peut rendre une dépendance optionnelle an ajoutantoptional
au nom du module de l'entrée de dépendance.Dépendances : org.javassist optional, org.apache.velocity
Option : export d'une dépendance
On peut exporter une dépendance en ajoutantexport
au nom du module de l'entrée de dépendance.Dépendences : org.javassist, org.apache.velocity export
Procédure 3.2. Ajouter une configuration de dépendance à jboss-deployment-structure.xml
Ajouter
jboss-deployment-structure.xml
Si l'application n'a pas de fichierjboss-deployment-structure.xml
, créer un nouveau fichier nomméjboss-deployment-structure.xml
et l'ajouter au projet. Ce fichier est un fichier XML ayant l'élément racine de<jboss-deployment-structure>
.<jboss-deployment-structure> </jboss-deployment-structure>
Pour une application web (WAR), ajouter ce fichier au répertoireWEB-INF
. Pour une archive EJB (JAR), l'ajouter au répertoireMETA-INF
.Ajouter une section de dépendances
Créer un élément<deployment>
à l'intérieur de la racine du document et un élément<dependencies>
également.Ajouter les éléments du module
Dans le nœud de dépendances, ajouter un élément de module pour chaque dépendance du module. Définir l'attributname
au nom du module.<module name="org.javassist" />
Option : rendre une dépendance optionnelle
On peut rendre une dépendance optionnelle en ajoutant l'attributoptional
à l'entrée du module, avec la valeurTRUE
. La valeur par défaut de cet attribut estFALSE
.<module name="org.javassist" optional="TRUE" />
Option : export d'une dépendance
On peut exporter une dépendance en ajoutant l'attributoptional
à l'entrée du module, avec la valeurTRUE
. La valeur par défaut de cet attribut estFALSE
.<module name="org.javassist" export="TRUE" />
Exemple 3.3. jboss-deployment-structure.xml avec deux dépendances
<jboss-deployment-structure> <deployment> <dependencies> <module name="org.javassist" /> <module name="org.apache.velocity" export="TRUE" /> </dependencies> </deployment> </jboss-deployment-structure>
3.3. Générer des entrées MANIFEST.MF en utilisant Maven
MANIFEST.MF
avec une entrée Dependencies
. Ce procédé ne génère pas automatiquement la liste de dépendances, il crée seulement le fichier MANIFEST.MF
avec les informations spécifiées dans le fichier pom.xml
.
Conditions préalables
- Vous devez déjà posséder un projet Maven en cours.
- Le projet Maven doit utiliser l'un des plug-ins JAR, EJB, ou WAR (
maven-jar-plugin
,maven-ejb-plugin
,maven-war-plugin
). - Vous devez connaître le nom des dépendances de module du projet. Voir Section 3.8.2, « Les modules inclus » pour obtenir la liste des modules statiques inclus dans JBoss EAP 6. Si le module est dans un autre déploiement, voir Section 3.1.7, « Nommage de modules dynamiques » pour déterminer le nom du module.
Procédure 3.3. Générer un fichier MANIFEST.MF contenant des dépendances de module.
Ajouter une configuration
Ajouter la configuration suivante à la configuration du plug-in de l'empaquetage dans le fichierpom.xml
du projet.<configuration> <archive> <manifestEntries> <Dependencies></Dependencies> </manifestEntries> </archive> </configuration>
Liste de dépendances
Ajouter la liste des dépendances de module dans l'élement <Dependencies>. Utiliser le même format utilisé lors de l'ajout des dépendances dans leMANIFEST.MF
. Veuillez consulter Section 3.2, « Ajouter une dépendance de module explicite à un déploiement » pour plus d'informations sur ce format.<Dependencies>org.javassist, org.apache.velocity</Dependencies>
Build de projet
Procédez au build de projet en utilisant l'objectif d'assemblage de Maven.[Localhost ]$ mvn assembly:assembly
MANIFEST.MF
avec les dépendances de module spécifiées.
Exemple 3.4. Dépendances de module configurées dans pom.xml
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <archive> <manifestEntries> <Dependencies>org.javassist, org.apache.velocity</Dependencies> </manifestEntries> </archive> </configuration> </plugin> </plugins>
3.4. Empêcher qu'un module soit chargé implicitement
Conditions préalables
- Vous devez déjà avoir un projet informatique qui fonctionne et dont vous souhaitez exclure une dépendance.
- Vous devez connaître le nom du module à exclure. Voir Section 3.8.1, « Dépendances de modules implicites » pour obtenir une liste des dépendances implicites et de leurs conditions.
Procédure 3.4. Ajouter une configuration d'exclusion de dépendances de jboss-deployment-structure.xml
- Si l'application n'a pas de fichier
jboss-deployment-structure.xml
, créer un nouveau fichier intituléjboss-deployment-structure.xml
et ajoutez-le au projet. Ce fichier est un fichier XML ayant comme élément root<jboss-deployment-structure>
.<jboss-deployment-structure> </jboss-deployment-structure>
Pour une application web (WAR), ajouter ce fichier au répertoireWEB-INF
. Pour une archive EJB (JAR), l'ajouter au répertoireMETA-INF
. - Créer un élément
<deployment>
dans la racine de l'élément et un<exclusions>
à l'intérieur.<deployment> <exclusions> </exclusions> </deployment>
- Dans l'élément d'exclusion, ajouter un élément
<module>
pour chaque module à exclure. Définir l'attributname
au nom du module.<module name="org.javassist" />
Exemple 3.5. Exclusion de deux modules
<jboss-deployment-structure> <deployment> <exclusions> <module name="org.javassist" /> <module name="org.dom4j" /> </exclusions> </deployment> </jboss-deployment-structure>
3.5. Exclure un sous-système d'un déploiement
Ce sujet traite des étapes nécessaires pour exclure un sous-système d'un déploiement. Pour ce faire, il convient de modifier le fichier de configuration jboss-deployment-structure.xml
. Le fait d'exclure un sous-système crée le même effet que de le retirer, sauf qu'il ne s'applique qu'à un seul déploiement.
Procédure 3.5. Exclure un sous-système
- Ouvrir le fichier
jboss-deployment-structure.xml
dans un éditeur de texte. - Ajouter le XML suivant dans les balises de <deployment> :
<exclude-subsystems> <subsystem name="SUBSYSTEM_NAME" /> </exclude-subsystems>
- Enregistrer le fichier
jboss-deployment-structure.xml
Le sous-système a bien été exclus. Les processeurs d'unité de déploiement du sous-système n'exécuteront plus sur le déploiement.
Exemple 3.6. Exemple d'un fichier jboss-deployment-structure.xml
.
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2"> <ear-subdeployments-isolated>true</ear-subdeployments-isolated> <deployment> <exclude-subsystems> <subsystem name="resteasy" /> </exclude-subsystems> <exclusions> <module name="org.javassist" /> </exclusions> <dependencies> <module name="deployment.javassist.proxy" /> <module name="deployment.myjavassist" /> <module name="myservicemodule" services="import"/> </dependencies> <resources> <resource-root path="my-library.jar" /> </resources> </deployment> <sub-deployment name="myapp.war"> <dependencies> <module name="deployment.myear.ear.myejbjar.jar" /> </dependencies> <local-last value="true" /> </sub-deployment> <module name="deployment.myjavassist" > <resources> <resource-root path="javassist.jar" > <filter> <exclude path="javassist/util/proxy" /> </filter> </resource-root> </resources> </module> <module name="deployment.javassist.proxy" > <dependencies> <module name="org.javassist" > <imports> <include path="javassist/util/proxy" /> <exclude path="/**" /> </imports> </module> </dependencies> </module> </jboss-deployment-structure>
3.6. Utiliser le chargeur de classes par programmation dans un développement
3.6.1. Chargement des classes et des ressources par programmation dans le déploiement.
- Charger une classe en utilisant la méthode Class.forName()
- Vous pouvez utiliser la méthode
Class.forName()
pour charger ou initialiser les classes par programmation. Cette méthode comprend deux signatures.La signature à trois arguments est la méthode recommandée pour charger une classe par programmation. Cette signature vous permet de contrôler si vous souhaitez que la classe cible soit initialisée pendant le chargement. Il est également plus efficace d'obtenir et de fournir le chargeur de classe parce que la JVM n'a pas besoin d'examiner la pile des appels pour déterminer quel chargeur de classe utiliser. En supposant que la classe contenant le code se nomme- Class.forName(String className)
- Cette signature ne prend en compte qu'un seul paramètre, le nom de la classe que vous devez charger. Avec cette méthode de signature, la classe est chargée par le chargeur de classes et initialise la classe nouvellement chargée par défaut.
- Class.forName(String className, boolean initialize, ClassLoader loader)
- Cette signature s'attend à recevoir trois paramètres : le nom de la classe, une valeur booléenne qui indique si on doit initialiser la classe, et le ClassLoader qui doit charger la classe.
CurrentClass
, vous pourrez obtenir le chargeur de classes de la classe par la méthodeCurrentClass.class.getClassLoader()
.L'exemple suivant donne un exemple de chargeur de classes qui puisse charger et initialiser la classeTargetClass
:Exemple 3.7. Fournir un chargeur de classes pour télécharger et initialiser les TargetClass.
Class<?> targetClass = Class.forName("com.myorg.util.TargetClass", true, CurrentClass.class.getClassLoader());
- Chercher toutes les ressources avec un Prénom
- Si vous connaissez le nom ou le chemin de la ressource, la meilleure façon de la charger directement serait d'utiliser la classe JDK ou l'API Classloader.
- Charger une seule ressource
- Pour charger une seule ressource qui se trouve dans le même répertoire que votre classe ou dans une autre classe de votre déploiement, vous pouvez utiliser la méthode
Class.getResourceAsStream()
.Exemple 3.8. Charger une seule ressource dans votre déploiement.
InputStream inputStream = CurrentClass.class.getResourceAsStream("targetResourceName");
- Charger toutes les instances en une ressource unique
- Pour charger toutes les instances d'une même ressource qui sont visibles par le chargeur de classe de votre déploiement, utilisez la méthode
Class.getClassLoader retourne ().getResources(String resourceName)
, oùresourceName
est le chemin d'accès qualifié complet de la ressource. Cette méthode retourne une énumération de tous les objetsURL
pour les ressources accessibles par le chargeur de classe du prénom donné. Vous pouvez ensuite parcourir le tableau des URL pour ouvrir chaque flux à l'aide de la méthodeopenStream()
.Exemple 3.9. Charger toutes les instances d'une ressource et itérer le résultat.
Enumeration<URL> urls = CurrentClass.class.getClassLoader().getResources("full/path/to/resource"); while (urls.hasMoreElements()) { URL url = urls.nextElement(); InputStream inputStream = null; try { inputStream = url.openStream(); // Process the inputStream ... } catch(IOException ioException) { // Handle the error } finally { if (inputStream != null) { try { inputStream.close(); } catch (Exception e) { // ignore } } } }
Note
Comme les instances URL sont chargées à partir du stockage local, il n'est pas utile d'utiliseropenConnection()
ou des méthodes semblables. Les flux sont plus faciles à utiliser et minimisent la complexité du code.
- Charger un fichier de classe à partir d'un chargeur de classes
- Si une classe a déjà été chargée, vous pouvez charger le fichier de classe qui correspond à cette classe en utilisant la syntaxe suivante :Si la classe n'a pas encore été chargée, vous devrez utiliser le chargeur de classes et en interpréter le chemin d'accès :
Exemple 3.10. Charger un fichier de classe déjà chargée.
InputStream inputStream = CurrentClass.class.getResourceAsStream(TargetClass.class.getSimpleName() + ".class");
Exemple 3.11. Charger un fichier de classe d'une classe qui n'a pas été chargée.
String className = "com.myorg.util.TargetClass" InputStream inputStream = CurrentClass.class.getClassLoader().getResourceAsStream(className.replace('.', '/') + ".class");
3.6.2. Itérer les ressources par programmation dans un déploiement.
MANIFEST.MF
:
Dépendences: org.jboss.modulesIl est important de noter que malgré que ces API fournissent une flexibilité grandissante, ils exécuteront bien plus lentement qu'une recherche de chemin d'accès directe.
- Lister les ressources du déploiement et de toutes les importations.
- Il y a des moments où il n'est pas possible de rechercher des ressources par le chemin exact. Par exemple, le chemin d'accès exact n'est peut être pas connu ou vous devrez peut-être examiner plus d'un fichier dans un chemin d'accès donné. Dans ce cas, la bibliothèque de modules de JBoss fournit plusieurs API pour une itération de toutes les ressources de déploiement. Vous pouvez parcourir les ressources dans un déploiement en utilisant une des deux méthodes.
- Itérer toutes les ressources qui se trouvent dans un seul module
- La méthode
ModuleClassLoader.iterateResources()
itère toutes les ressources au sein de ce chargeur de classes de module. Cette méthode accepte deux arguments : le nom du répertoire de départ à rechercher et une valeur booléenne qui spécifie s'il doit agir récursivement dans les sous-répertoires.L'exemple suivant montre comment on obtient le ModuleClassLoader ou l'itérateur pour les ressources qui se trouvent dans le répertoirebin/
, récursivement dans les sous-répertoires.L'itérateur résultant peut être utilisé pour examiner chaque ressource correspondante et pour chercher son nom et sa taille (si disponible), pour ouvrir une transmission à lire, ou pour obtenir l'URL d'une ressource.Exemple 3.12. Chercher les ressources du répertoire "bin" récursivement dans les sous-répertoires.
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Iterator<Resource> mclResources = moduleClassLoader.iterateResources("bin",true);
- Itérer toutes les ressources qui se trouvent dans un seul module et dans les ressources importées
- La méthode
Module.iterateResources()
itère toutes les ressources au sein de ce chargeur de classes de module, y compris les ressources qui sont importées dans le module. Cette méthode renvoie un ensemble beaucoup plus vaste que la méthode précédente. Cette méthode requiert un argument: un filtre qui rétrécit le résultat à un modèle spécifique. Alternativement, les PathFilters.acceptAll() peuvent être fournis pour retourner l'ensemble.Exemple 3.13. Chercher toutes les ressources de ce module, y compris les importations.
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Module module = moduleClassLoader.getModule(); Iterator<Resource> moduleResources = module.iterateResources(PathFilters.acceptAll());
- Chercher toutes les ressources qui correspondent à un modèle particulier
- Si vous avez besoin de trouver des ressources spécifiques dans votre déploiement ou dans son importation complète, vous devrez filtrer l'itération de la ressource. Les API de filtrage de JBoss Modules peuvent vous donner plusieurs outils pour y parvenir.
- Examiner toutes les dépendances
- Si vous devez examiner l'ensemble des dépendances, vous pouvez utiliser le paramètre
PathFilter
de la méthodeModule.iterateResources()
pour vérifier le nom de chaque ressource et trouver une correspondance. - Examiner les dépendances de déploiement
- Si vous devez chercher uniquement dans le déploiement, utilisez la méthode
ModuleClassLoader.iterateResources()
. Toutefois, vous devez utiliser des méthodes supplémentaires pour filtrer l'itérateur qui en résulte. La méthodePathFilters.filtered()
peut fournir une vue filtrée d'un itérateur de ressources dans ce cas. La classePathFilters
comprend plusieurs méthodes statiques pour créer et composer des filtres qui remplissent des fonctions diverses, y compris la recherche de chemins dépendants ou des correspondances exactes, ou encore correspondant à un motif "glob" Ant-style.
- Exemples de codes supplémentaires pour filtrer les ressources
- Les exemples suivants démontrent comment filtrer les ressources sur la base de critères différents.
Exemple 3.14. Trouver tous les noms qui comprennent "messages.properties" dans votre déploiement.
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Iterator<Resource> mclResources = PathFilters.filtered(PathFilters.match("**/messages.properties"), moduleClassLoader.iterateResources("", true));
Exemple 3.15. Trouver tous les noms qui comprennent "messages.properties" dans votre déploiement et dans vos importations.
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Module module = moduleClassLoader.getModule(); Iterator<Resource> moduleResources = module.iterateResources(PathFilters.match("**/message.properties));
Exemple 3.16. Trouver tous les fichiers qui se trouvent dans tout répertoire nommé "my-resources" de votre déploiement.
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Iterator<Resource> mclResources = PathFilters.filtered(PathFilters.match("**/my-resources/**"), moduleClassLoader.iterateResources("", true));
Exemple 3.17. Trouver tous les fichiers nommés "messages.properties" dans votre déploiement et dans vos importations.
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Module module = moduleClassLoader.getModule(); Iterator<Resource> moduleResources = module.iterateResources(PathFilters.any(PathFilters.match("**/messages"), PathFilters.match("**/errors"));
Exemple 3.18. Trouver tous les fichiers qui se trouvent dans un package spécifique de votre déploiement.
ModuleClassLoader moduleClassLoader = (ModuleClassLoader) TargetClass.class.getClassLoader(); Iterator<Resource> mclResources = moduleClassLoader.iterateResources("path/form/of/packagename", false);
3.7. Chargement de classe et sous-déploiements
3.7.1. Chargement de classes et de modules dans les EAR (Archives Enterprise)
- Chaque sous-déploiement WAR ou EJB JAR est un module.
- Le contenu du répertoire
lib/
de la racine de l'archive EAR est un module. On l'appelle un module parent.
- Les sous-déploiements WAR possédent des dépendances implicites sur le module parent et sur tout sous-déploiement JAR EJB.
- Les sous-déploiements EJB JAR possédent des dépendances implicites sur le module parent et sur tout sous-déploiement JAR EJB.
Important
Class-Path
dans le fichier MANIFEST.MF
de chaque sous-déploiement.
3.7.2. Isolement du chargeur de classes d'un sous-déploiement
3.7.3. Désactiver l'isolement du chargeur de classes d'un sous-déploiement dans un EAR
Important
Ajouter le fichier du descripteur de déploiement
Ajouter le fichier de descripteur de déploiementjboss-deployment-structure.xml
au répertoireMETA-INF
du EAR s'il n'existe pas déjà et ajouter le contenu suivant :<jboss-deployment-structure> </jboss-deployment-structure>
Ajouter l'élément
<ear-subdeployments-isolated>
Ajouter l'élément<ear-subdeployments-isolated>
au fichierjboss-deployment-structure.xml
s'il n'existe pas déjà dans le contenu defalse
.<ear-subdeployments-isolated>false</ear-subdeployments-isolated>
L'isolement de chargeur de classe de sous-déploiement sera maintenant désactivé pour le déploiement de cet EAR. Cela signifie que les sous-déploiements du EAR auront des dépendances automatiques sur chacun des sous-déploiements non-WAR.
3.8. Référence
3.8.1. Dépendances de modules implicites
Tableau 3.1. Dépendances de modules implicites
Sous-système responsable de l'ajout de la dépendance | Dépendances qui sont toujours ajoutées | Dépendances qui sont ajoutées conditionnellement | Conditions qui déclenchent l'ajout de dépendances |
---|---|---|---|
Serveur principal |
| | |
EE subsystem |
| | |
EJB 3 subsystem | |
|
La présence d'un ficher
ejb-jar.xml à des emplacements valides dans le déploiement, tel que mentionné dans les spécifications Java EE 6.
La présence d'EJB basés-annotations, comme :
@Stateless , @Stateful , @MessageDriven
|
Sous-système JAX-RS (RESTEasy) |
|
| La présence d'annotations JAX-RS dans le déploiement. |
Sous-système JCA |
|
| Le déploiement d'une archive d'adaptateur de ressources (RAR). |
Sous-système JPA (Hibernate) |
|
|
La présence de l'annotation
@PersistenceUnit ou @PersistenceContext , <persistence-unit-ref> ou encore d'un élément <persistence-context-ref> dans un descripteur de déploiement.
JBoss EAP 6 mappe les noms du fournisseur de persistance aux noms du module. Si vous nommez un fournisseur particulier dans le fichier
persistence.xml , une dépendance sera ajoutée au module qui convient. Si ce comportement ne convient pas, vous pourrez l'exclure par l'intermdiaire d'un fichier jboss-deployment-structure.xml .
|
Sous-système de journalisation |
| |
Ces dépendances sont toujours ajoutées à moins que l'attribut
add-logging-api-dependencies soit défini à false.
|
Sous-système SAR | |
| Le déploiement d'une archive SAR. |
Sous-système de sécurité |
| | |
Sous-système Web | |
| Le déploiement d'une archive WAR. JavaServer Faces (JSF) est ajouté uniquement si utilisé. |
Sous-système de Services Web |
| | |
Sous-système Weld (CDI) | |
| La présence d'un fichier beans.xml dans le déploiement. |
3.8.2. Les modules inclus
3.8.3. Référence de descripteur de déploiement de structure de déploiement de JBoss
- Définition des dépendances de modules explicites.
- Empêcher les dépendances implicites spécifiques de charger.
- Définir des modules supplémentaires à partir des ressources de ce déploiement.
- Modifier le comportement de l'isolation du sous-déploiement dans ce déploiement EAR.
- Ajouter des racines de ressources supplémentaires à un EAR.
Chapitre 4. Valves
4.1. Valves
- Les valves globales sont configurées au niveau serveur et s'appliquent à toutes les applications déployées dans le serveur. Les instructions sur la façon de configurer les valves globales se trouvent dans le guide Administration and Configuration Guide de JBoss EAP.
- Les valves configurées au niveau de l'application sont empaquetées dans le déploiement de l'application et n'affectent que l'application en question. Des instructions sur la façon de configurer des valves au niveau de l'application se trouvent dans le guide Development Guide de JBoss EAP.
4.2. Valves globales
4.3. Les valves d'authentification
org.apache.catalina.authenticator.AuthenticatorBase
et elle remplace la méthode authenticate(Request request, Response response, LoginConfig config)
.
4.4. Configurer une application web pour utiliser une valve.
jboss-web.xml
.
Important
Conditions préalables
- La valve doit être créée et incluse dans le chemin de classe de l'application. Pour ce faire, il convient de l'inclure dans le fichier WAR de l'application ou dans tout autre module ajouté comme dépendance. Les exemples de tels modules comprennent un module statique installé sur le serveur ou un fichier JAR dans le répertoire
lib/
d'une archive EAR si le WAR est déployé dans un EAR. - L'application doit inclure un descripteur de déploiement de
jboss-web.xml
.
Procédure 4.1. Configurer une application pour une valve locale.
Configuration d'une valve
Créer un élémentvalve
contenant l'élément enfantclass-name
au fichierjboss-web.xml
de l'application. Leclass-name
est le nom de la classe de valve.<valve> <class-name>VALVE_CLASS_NAME</class-name> </valve>
Exemple 4.1. Exemple d'élément de valve configuré dans le fichier jboss-web.xml
<valve> <class-name>org.jboss.security.negotiation.NegotiationAuthenticator</class-name> </valve>
Configurer une valve personnalisée
Si la valve possède des paramètres configurables, ajouter un élément enfantparam
à l'élémentvalve
pour chaque paramètre, en spécifiant leur nom et leur valeurparam-name
etparam-value
.Exemple 4.2. Exemple d'élément de valve personnalisé configuré dans le fichier jboss-web.xml
<valve> <class-name>org.jboss.web.tomcat.security.GenericHeaderAuthenticator</class-name> <param> <param-name>httpHeaderForSSOAuth</param-name> <param-value>sm_ssoid,ct-remote-user,HTTP_OBLIX_UID</param-value> </param> <param> <param-name>sessionCookieForSSOAuth</param-name> <param-value>SMSESSION,CTSESSION,ObSSOCookie</param-value> </param> </valve>
Exemple 4.3. Configuration valve jboss-web.xml
<valve> <class-name>org.jboss.samplevalves.RestrictedUserAgentsValve</class-name> <param> <param-name>restrictedUserAgents</param-name> <param-value>^.*MS Web Services Client Protocol.*$</param-value> </param> </valve>
4.5. Configurer une application web pour qu'elle utilise une valve d'authentification
web.xml
de l'application. Dans le cas le plus simple, la configuration web.xml
revient à utiliser une authentification BASIC
sauf que l'élément enfant auth-method
de login-config
est défini sous le nom de la valve qui effectue la configuration.
Conditions préalables
- La valve d'authentification devrait déjà être créée.
- Si la valve d'authentification est une valve globale, cette dernière devrait déjà être installée et configurée, et il convient de connaître le nom sous lequel elle a été configurée.
- Informez-vous du nom de domaine de la zone de sécurité que l'application utilise.
Procédure 4.2. Configurer une application pour utiliser une valve d'authentification
Configurer la valve
L'utilisation d'une valve locale nécessite une configuration dans le descripteur de déploiementjboss-web.xml
des applications. Voir Section 4.4, « Configurer une application web pour utiliser une valve. ».Cela n'est pas nécessaire pour l'utilisation d'une valve globale.Ajouter une configuration de sécurité à web.xml.
Ajouter la configuration de sécurité au fichier web.xml pour votre application en utilisant les éléments standards tels que la contrainte de sécurité, la configuration de l'identifiant et le rôle de la sécurité. Dans l'élément de configuration de l'identifiant, définir la valeur de la méthode d'identification en tant que nom de la valve d'identification. L'élément de nom de la zone doit également être défini en tant que nom de la zone de sécurité de JBoss utilisée par l'application.<login-config> <auth-method>VALVE_NAME</auth-method> <realm-name>REALM_NAME</realm-name> </login-config>
4.6. Créer une valve personnalisée
Procédure 4.3. Créer une valve personnalisée
Créer la classe Valve
Créer une sous-classe deorg.apache.catalina.valves.ValveBase
.package org.jboss.samplevalves; import org.apache.catalina.valves.ValveBase; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; public class RestrictedUserAgentsValve extends ValveBase { }
Mettre en place la méthode d'invocation
La méthodeinvoke()
est utilisée lorsque la valve est exécutée dans la pipeline. Les objets de requête et de réponse sont considérés comme des paramètres. Effectuer tout procédé et modification de requête et réponse ici.public void invoke(Request request, Response response) { }
Invoquer la prochaine étape de pipeline
La dernière étape que la méthode d'invocation doit effectuer est d'invoquer l'étape suivante de la pipeline et de transmettre les objets de requête et de réponse modifiés, en utilisant la méthodegetNext().invoke()
.getNext().invoke(request, response);
Option : indiquer les paramètres
Si la valve doit être configurable, activer cette option en ajoutant un paramètre. Pour ce faire, il convient d'ajouter une variable d'instance et une méthode setter pour chaque paramètre.private String restrictedUserAgents = null; public void setRestricteduserAgents(String mystring) { this.restrictedUserAgents = mystring; }
Exemple 4.4. Échantillon de valve personnalisée
package org.jboss.samplevalves; import java.io.IOException; import java.util.regex.Pattern; import javax.servlet.ServletException; import org.apache.catalina.valves.ValveBase; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; public class RestrictedUserAgentsValve extends ValveBase { private String restrictedUserAgents = null; public void setRestrictedUserAgents(String mystring) { this.restrictedUserAgents = mystring; } public void invoke(Request request, Response response) throws IOException, ServletException { String agent = request.getHeader("User-Agent"); System.out.println("user-agent: " + agent + " : " + restrictedUserAgents); if (Pattern.matches(restrictedUserAgents, agent)) { System.out.println("user-agent: " + agent + " matches: " + restrictedUserAgents); response.addHeader("Connection", "close"); } getNext().invoke(request, response); } }
Chapitre 5. La journalisation pour les développeurs
5.1. Introduction
5.1.1. Journalisation
5.1.2. Frameworks de journalisations d'applications pris en charge par JBoss LogManager
- JBoss Logging - inclus avec JBoss EAP 6
- Apache Commons Logging - http://commons.apache.org/logging/
- Simple Logging Facade Java (SLF4J) - http://www.slf4j.org/
- Apache log4j - http://logging.apache.org/log4j/1.2/
- Java SE Logging (java.util.logging) - http://download.oracle.com/javase/6/docs/api/java/util/logging/package-summary.html
5.1.3. Niveaux de journalisation
TRACE
, DEBOG
, INFO
, ATTENTION
, ERREUR
et FATAL
.
ATTENTION
enregistrera uniquement les messages des niveaux ATTENTION
, ERREUR
et FATAL
.
5.1.4. Niveaux de journalisation pris en charge
Tableau 5.1. Niveaux de journalisation pris en charge
Niveau de journalisation | Valeur | Description |
---|---|---|
FINESSE MAX | 300 |
-
|
PLUS FIN | 400 |
-
|
TRACE | 400 |
Utilisé pour des messages qui fournissent des informations détaillées sur l'état d'exécution d'une application. Les messages de journalisation
TRACE sont habituellement capturés uniquement lors du débogage d'une application.
|
DEBOG | 500 |
Utilisé pour des messages qui indiquent des demandes individuelles de progrès ou des activités d'une application. Les messages de journalisation
DEBUG ne sont habituellement capturés que lors du débogage d'une application.
|
FINESSE | 500 |
-
|
CONFIG | 700 |
-
|
INFO | 800 |
Utilisé pour des messages qui indiquent la progression globale de l'application. Souvent utilisé pour le démarrage de l'application, la fermeture et autres événements majeurs de cycle de vie.
|
AVERTISSEMENT | 900 |
Utilisé pour indiquer une situation qui n'est pas en erreur, mais n'est pas considérée comme idéale. Peut indiquer des circonstances qui peuvent entraîner des erreurs dans le futur.
|
ATTENTION | 900 |
-
|
ERREUR | 1000 |
Utiliser pour indiquer une erreur qui s'est produite et qui puisse empêcher l'activité actuelle ou la demande de se remplir, mais qui n'empêchera pas l'application d'exécuter.
|
SÉVÈRE | 1000 |
-
|
FATALE | 1100 |
Utiliser pour indiquer les événements qui pourraient entraîner des défaillances de services critiques ou la fermeture de l'application, ou qui pourraient entraîner la fermeture de la plateforme JBoss EAP 6.
|
5.1.5. Emplacements de fichiers de journalisation par défaut
Tableau 5.2. Fichier de journalisation par défaut d'un serveur autonome
Fichier journal | Description |
---|---|
EAP_HOME/standalone/log/server.log |
Journal du serveur. Contient les messages de journalisation de serveur, dont les messages de démarrage de serveur.
|
EAP_HOME/standalone/log/gc.log |
Journalisation de Garbage collection. Contient des informations sur tous les nettoyagess de mémoire.
|
Tableau 5.3. Fichiers de journalisation par défaut d'un domaine géré
Fichier journal | Description |
---|---|
EAP_HOME/domain/log/host-controller.log |
Journal d'amorçage du contrôleur hôte. Contient les messages de journalisation liés au démarrage du contrôleur hôte.
|
EAP_HOME/domain/log/process-controller.log |
Journal d'amorçage du contrôleur de processus. Contient les messages de journalisation liés au démarrage du contrôleur de processus.
|
EAP_HOME/domain/servers/SERVERNAME/log/server.log |
Le journal du serveur pour le serveur nommé. Contient les messages de journalisation de ce serveur, dont les messages de démarrage de serveur.
|
5.2. Journalisation dans le JBoss Logging Framework
5.2.1. JBoss Logging
5.2.2. Fonctionnalités de JBoss Logging
- Fournit un enregistreur d'événements de saisie ("typed") facile d'utilisation.
- Support total pour l'internationalisation et la localisation. Les traducteurs travaillent sur des lots de messages dans des fichiers de propriétés, tandis que les développeurs peuvent travailler sur des interfaces et des annotations.
- Outils « buid-time » pour générer les enregistreurs d'événements en saisie pour la production, et la génération runtime d'enregistreurs d'événements pour le développement.
5.2.3. Ajouter une journalisation à une application par JBoss Logging
org.jboss.logging.Logger
) et utiliser la méthode appropriée de cet objet. Cette tâche décrit les étapes nécessaires pour ajouter un support pour ceci à votre application.
Conditions préalables
- Si vous utilisez Maven en tant que système de build, il convient que le projet soit déjà configuré pour inclure le référentiel JBoss Maven. Voir Section 2.3.2, « Configurer le référentiel JBoss EAP 6 Platform Maven Repository par les paramètres de configuration de Maven »
- Les fichiers JAR de JBoss Logging doivent se trouver dans le chemin de build d'application. La façon dont vous procédrez dépendra de votre décision de générer votre application avec Red Hat JBoss Developer Studio ou avec Maven.
- Quand vous générez avec Red Hat JBoss Developer Studio vous pouvez procéder en sélectionnant Project -> Properties à partir du menu Red Hat JBoss Developer Studio, en sélectionnant Targeted Runtimes et en veillant bien à vérifier le temps d'exécution de JBoss EAP 6.
- Quand vous générez avec Maven, vous pouvez procéder en ajoutant la configuration de dépendance suivante au fichier
pom.xml
de votre projet.<dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.1.2.GA-redhat-1</version> <scope>provided</scope> </dependency>
Vous n'avez pas besoin d'inclure les JAR de l'application générée car JBoss EAP 6 les fournit aux applications qui sont déployées.
Ajouter Imports
Ajouter les déclarations d'importation des espace-noms de classe JBoss Logging que vous allez utiliser. Vous devrez importer au minimumimport org.jboss.logging.Logger
.import org.jboss.logging.Logger;
Créer un objet Logger
Créer une instance deorg.jboss.logging.Logger
et l'initialiser en utilisant la méthode statiqueLogger.getLogger(Class)
. Red Hat vous recommande de la créer en tant que variable à instance unique pour chaque classe.private static final Logger LOGGER = Logger.getLogger(HelloWorld.class);
Ajouter les messages de journalisation
Ajouter des appels aux méthodes de l'objetLogger
à votre code, là où vous souhaitez qu'il envoie des messages. L'objetLogger
comprend un certain nombre de méthodes contenant des paramètres différents suivant les types de messages. Les plus faciles à utiliser sont les suivants :debog(message objet)
info(message objet)
erreur(message objet)
trace(message objet)
fatal(message objet)
Ces méthodes envoient un message de journalisation avec un niveau de journalisation correspondant et le paramètremessage
comme string.LOGGER.error("Configuration file not found.");
Pour obtenir une liste complète des méthodes JBoss Logging, consulter le packageorg.jboss.logging
dans JBoss EAP 6 API Documentation.
Exemple 5.1. Utilisation de JBoss Logging quand on ouvre un fichier de propriétés
import org.jboss.logging.Logger; public class LocalSystemConfig { private static final Logger LOGGER = Logger.getLogger(LocalSystemConfig.class); public Properties openCustomProperties(String configname) throws CustomConfigFileNotFoundException { Properties props = new Properties(); try { LOGGER.info("Loading custom configuration from "+configname); props.load(new FileInputStream(configname)); } catch(IOException e) //catch exception in case properties file does not exist { LOGGER.error("Custom configuration file ("+configname+") not found. Using defaults."); throw new CustomConfigFileNotFoundException(configname); } return props; }
5.3. La journalisation par déploiement
5.3.1. La journalisation par déploiement
5.3.2. La journalisation par déploiement vers une application
logging.properties
au déploiement. Ce fichier de configuration est conseillé car il peut être utilisé avec n'importe quelle façade de journalisation dans la mesure où JBoss Log Manager est le gestionnaire de journalisation sous-jacent utilisé.
Simple Logging Facade for Java (SLF4J)
ou Apache log4j
, le fichier de configuration logging.properties
est approprié. Si vous utilisez appenders de Apache log4j, alors la configuration fichier log4j.properties
sera requise. Le fichier de configuration jboss-logging.properties
est pris en charge uniquement pour les déploiements existants hérités.
Procédure 5.1. Ajouter le fichier de configuration à l'application
Le répertoire auquel le fichier de configuration est ajouté dépend de la méthode de déploiement :
EAR
,WAR
ouJAR
.Déploiement
EAR
Copier le fichier de configuration de journalisation dans le répertoireMETA-INF
.Déploiement
WAR
ouJAR
Copier le fichier de configuration de journalisation dans le répertoireMETA-INF
ouWEB-INF/classes
.
5.3.3. Exemple de fichier logging.properties
# Additional loggers to configure (the root logger is always configured) loggers= # Root logger configuration logger.level=INFO logger.handlers=FILE # A handler configuration handler.FILE=org.jboss.logmanager.handlers.FileHandler handler.FILE.level=ALL handler.FILE.formatter=PATTERN handler.FILE.properties=append,autoFlush,enabled,suffix,fileName handler.FILE.constructorProperties=fileName,append handler.FILE.append=true handler.FILE.autoFlush=true handler.FILE.enabled=true handler.FILE.fileName=${jboss.server.log.dir}/app.log # The formatter to use formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter formatter.PATTERN.properties=pattern formatter.PATTERN.constructorProperties=pattern formatter.PATTERN.pattern=%d %-5p %c: %m%n
5.4. Profils de journalisation
5.4.1. Profils de journalisation
Important
- Un nom unique. Ceci est requis.
- N'importe quel nombre de log handlers.
- N'importe quelle catégorie log.
- Un root logger maximum.
MANIFEST.MF
, en utilisant l'attribut logging-profile
.
5.4.2. Spécifier un profil de journalisation dans une application
MANIFEST.MF
.
Conditions préalables :
- Vous devez connaître le nom du profil de journalisation qui a été défini sur le serveur pour cette application. Demandez à votre administrateur de systèmes le nom du profil à utiliser.
Procédure 5.2. Ajouter une configuration de profil de journalisation à une application
Modifier
MANIFEST.MF
Si votre application ne possède pas de fichierMANIFEST.MF
: le créer avec le contenu suivant, en remplaçant NAME par le nom de profil qui convient.Manifest-Version: 1.0 Logging-Profile: NAME
Si votre application contient déjà un fichierMANIFEST.MF
: ajouter la ligne suivante, en remplaçant NAME par le nom du profil qui convient.Logging-Profile: NAME
Note
maven-war-plugin
, vous pourrez mettre votre fichier MANIFEST.MF dans src/main/resources/META-INF/
et ajouter la configuration suivante à votre fichier pom.xml
.
<plugin> <artifactId>maven-war-plugin</artifactId> <configuration> <archive> <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin>
Chapitre 6. Internationalisation et localisation
6.1. Introduction
6.1.1. Internationalisation
6.1.2. Localisation
6.2. Outils JBoss Logging
6.2.1. Aperçu
6.2.1.1. JBoss Logging Tools - Internationalisation et Localisation
org.jboss.logging
. Il n'est pas nécessaire d'implémenter les interfaces, JBoss Logging Tools le fait au moment de la compilation. Une fois définies, vous pouvez utiliser ces méthodes pour enregistrer des messages ou obtenir des objets d'exception dans votre code.
6.2.1.2. JBoss Logging Tools Quickstart
logging-tools
, contient un simple projet Maven qui démontre les fonctionnalités de JBoss Logging Tools. A été utilisé extensivement dans cette documentation pour les exemples de code.
6.2.1.3. Message Logger
@org.jboss.logging.MessageLogger
.
6.2.1.4. Lot de messages
@org.jboss.logging.MessageBundle
.
6.2.1.5. Messages de journalisation internationalisés
@LogMessage
et @Message
et spécifier le message de journalisation en utilisant l'attribut de la valeur de @Message
. Les messages de journalisation internationalisés sont localisés en fournissant des traductions dans un fichier de propriétés.
6.2.1.6. Exceptions internationalisées
6.2.1.7. Messages internationalisés
6.2.1.8. Fichiers de propriétés de traduction
6.2.1.9. Codes de projets de JBoss Logging Tools
projectCode
de l'annotation @MessageLogger
.
6.2.1.10. Ids de messages de JBoss Logging Tools
id
de l'annotation @Message
.
6.2.2. Création de loggers, de messages ou d'exceptions internationalisés
6.2.2.1. Créer des messages log internationalisés
logging-tools
pour trouver un exemple complet.
Prérequis :
- Vous devez déjà posséder un projet Maven en cours. Voir Section 6.2.6.1, « Configuration Maven JBoss Logging Tools ».
- Le projet doit avoir la configuration Maven qui convient pour JBoss Logging Tools.
Procédure 6.1. Créer un lot de messages log internationalisés
Créer une interface de Message Logger
Ajouter une interface Java à votre projet pour contenir les définitions de messages log. Définir l'interface de façon descriptive pour les messages log qui seront définis à l'intérieur.L'interface de messages log ont les prérequis suivants :- Doit être annotée par
@org.jboss.logging.MessageLogger
. - Doit étendre
org.jboss.logging.BasicLogger
. - L'interface doit définir un champ qui est un Logger typed quiimpléemnte cette interface. Procédez par la méthode
getMessageLogger()
deorg.jboss.logging.Logger
.
package com.company.accounts.loggers; import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; import org.jboss.logging.MessageLogger; @MessageLogger(projectCode="") interface AccountsLogger extends BasicLogger { AccountsLogger LOGGER = Logger.getMessageLogger( AccountsLogger.class, AccountsLogger.class.getPackage().getName() ); }
Ajouter les définitions de méthode
Ajouter une définition de méthode à l'interface de chaque message log. Nommez chaque méthode descriptivement par rapport au message log qu'elle représente.Chaque méthode a les prérequis suivants :- La méthode doit renvoyer
void
. - La méthode doit être annotée par
@org.jboss.logging.LogMessage
. - La méthode doit être annotée par
@org.jboss.logging.Message
. - L'attribut de
@org.jboss.logging.Message
contient le message log par défaut. Il s'agit du message qui est utilisé s'il n'y a pas de traduction.
@LogMessage @Message(value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
Le niveau de journalisation par défaut estINFO
.Invoquer les méthodes
Ajouter les appels aux méthodes d'interface dans votre code là où les messages doivent être journalisés. Il n'est pas utile de créer des implémentations des interfaces, le processeur d'annotations le fait pour vous quand le projet est compilé.AccountsLogger.LOGGER.customerQueryFailDBClosed();
Les loggers personnalisés sont des sous-classes de BasicLogger, donc les méthodes de journalisation deBasicLogger
(debug()
,error()
etc) peuvent également être utilisées. Il n'est pas utile de créer d'autres loggers pour enregistrer les messages non internationalisés.AccountsLogger.LOGGER.error("Invalid query syntax.");
6.2.2.2. Créer et utiliser des messages internationalisés
logging-tools
pour trouver un exemple complet.
Pré-requis
- Vous avez un projet Maven utilisant le référentiel JBoss EAP 6. Voir Section 2.3.2, « Configurer le référentiel JBoss EAP 6 Platform Maven Repository par les paramètres de configuration de Maven ».
- La configuration Maven requise pour JBoss Logging Tools a été ajoutée. Voir Section 6.2.6.1, « Configuration Maven JBoss Logging Tools ».
Procédure 6.2. Créer et utiliser des messages internationalisés
Créer une interface pour les exceptions.
JBoss Logging Tools définit les messages internationalisés dans les interfaces. Nommer chaque interface de manière descriptive pour les messages qui seront définis à l'intérieur.L'interface possède les prérequis suivants :- Elle doit être déclarée publique
- Elle doit être annotée par
@org.jboss.logging.MessageBundle
. - L'interface doit définir un champ qui corresponde à un lot de messages du même type que l'interface.
@MessageBundle(projectCode="") public interface GreetingMessageBundle { GreetingMessageBundle MESSAGES = Messages.getBundle(GreetingMessageBundle.class); }
Ajouter les définitions de méthode
Ajouter une définition de méthode dans l'interface de chaque message.Chaque méthode a les prérequis suivants :- Elle doit renvoyer un objet de type
String
. - La méthode doit être annotée par
@org.jboss.logging.Message
. - L'attribut
@org.jboss.logging.Message
doit être défini à la valeur par défaut du message. Il s'agit du message qui est utilisé si aucune traduction n'est disponible.
@Message(value = "Hello world.") String helloworldString();
Méthodes d'invocation
Invoquer les méthodes d'interface dans votre application quand vous aurez besoin d'obtenir le message.System.console.out.println(helloworldString());
6.2.2.3. Créer des exceptions personnalisées
logging-tools
pour trouver un exemple complet.
Procédure 6.3. Créer et utiliser des exceptions internationalisées
Ajouter une configuration JBoss Logging Tools
Ajouter la configuration de projet qui convient pour prendre en charge JBoss Logging Tools. Voir Section 6.2.6.1, « Configuration Maven JBoss Logging Tools »Créer une interface pour les exceptions.
JBoss Logging Tools définit les exceptions internationalisées dans les interfaces. Nommer chaque interface de façon descriptive pour les exceptions qui seront décrites à l'intérieur.L'interface possède les prérequis suivants :- Elle doit être déclarée
public
. - Elle doit être annotée par
@org.jboss.logging.MessageBundle
. - L'interface doit définir un champ qui corresponde à un lot de messages du même type que l'interface.
@MessageBundle(projectCode="") public interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); }
Ajouter les définitions de méthode
Ajouter une définition de méthode à l'interface pour chaque exception. Nommez chaque méthode de façon descriptive pour chaque exception qu'elle représente.Chaque méthode a les prérequis suivants :- Elle doit renvoyer un objet du type
Exception
ou bien un sous-type d'Exception
. - La méthode doit être annotée par
@org.jboss.logging.Message
. - L'attribut de
@org.jboss.logging.Message
doit être défini à la valeur du message d'exception par défaut. Il s'agit du message qui est utilisé s'il n'y a pas de traduction. - Si l'exception est retournée à un constructeur qui nécessite des paramètres en plus d'une chaîne de message, alors ces paramètres doivent être fournis dans la définition de méthode à l'aide de l'annotation
@param
. Les paramètres doivent être du même type et du même ordre que le constructeur.
@Message(value = "The config file could not be opened.") IOException configFileAccessError(); @Message(id = 13230, value = "Date string '%s' was invalid.") ParseException dateWasInvalid(String dateString, @Param int errorOffset);
Méthodes d'invocation
Invoquer les méthodes d'interface de votre code quand vous devrez obtenir une des exceptions. Les méthodes ne lancent pas d'exceptions, elles envoient l'objet d'exception que vous pourrez alors envoyer vous-même.try { propsInFile=new File(configname); props.load(new FileInputStream(propsInFile)); } catch(IOException ioex) //in case props file does not exist { throw ExceptionBundle.EXCEPTIONS.configFileAccessError(); }
6.2.3. Localisation de loggers, messages ou exceptions internationalisés
6.2.3.1. Générer des nouveaux fichiers de propriétés de traduction avec Maven
logging-tools
pour trouver un exemple complet.
Conditions préalables :
- Vous devez déjà posséder un projet Maven en cours.
- Le projet devra avoir été configuré pour JBoss Logging Tools.
- Le projet doit contenir une ou plusieurs interfaces qui définissent des exceptions ou des messages de journalisation internationalisés
Procédure 6.4. Générer des nouveaux fichiers de propriétés de traduction avec Maven
Ajouter la configuration Maven
Ajouter l'argument de compilateur-AgenereatedTranslationFilePath
à la configuration du plug-in du compilateur Maven et lui assigner le chemin d'accès où les nouveaux fichiers devront être créés.<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> <compilerArgument> -AgeneratedTranslationFilesPath=${project.basedir}/target/generated-translation-files </compilerArgument> <showDeprecation>true</showDeprecation> </configuration> </plugin>
La configuration ci-dessus va créer des nouveaux fichiers dans le répertoiretarget/generated-translation-files
de votre projet Maven.Créer votre projet
Créer votre projet en utilisant Maven.[Localhost]$ mvn compile
@MessageBundle
ou @MessageLogger
. Les nouveaux fichiers sont créés dans un sous-répertoire qui correspond au package Java dans lequel chaque interface est déclarée.
InterfaceName
comme nom d'interface pour laquelle ce fichier a été créé : InterfaceName.i18n_locale_COUNTRY_VARIANT.properties
.
6.2.3.2. Traduire un logger, une exception ou un message internationalisé
logging-tools
pour trouver un exemple complet.
Pré-requis
- Vous devez déjà posséder un projet Maven en cours.
- Le projet devra avoir été configuré pour JBoss Logging Tools.
- Le projet devra contenir une ou plusieurs interfaces qui définissent les exceptions ou message log d'internationalisation.
- Le projet devra être configuré pour générer des fichiers de propriétés modèles.
Procédure 6.5. Traduire un message, une exception ou un message internationalisé
Créer des fichiers de propriétés modèles
Exécuter la commandemvn compile
pour créer les modèles de fichiers de propriétés de traduction.Ajouter le fichier modèle à votre projet.
Copier le modèle des interfaces que vous souhaitez traduire depuis le répertoire où elles ont été créées dans le répertoiresrc/main/resources
de votre projet. Les fichiers de propriétés doivent figurer dans le même package des interfaces qu'ils traduisent.Renommer le fichier modèle copié
Renommer la copie du fichier modèle selon la traduction qu'il contient. Par exemple,GreeterLogger.i18n_fr_FR.properties
.Traduire le contenu du modèle
Modifier le nouveau fichier de propriétés de traduction de manière à contenir la traduction appropriée.# Level: Logger.Level.INFO # Message: Hello message sent. logHelloMessageSent=Bonjour message envoyé.
Répéter les étapes deux, trois et quatre pour chaque traduction de chaque lot exécuté.
target/generated-sources/annotations/
.
6.2.4. Personnalisation des messages de journalisation internationalisés
6.2.4.1. Ajouter les ids de messages et les codes de projets aux messages de journalisation
logging-tools
pour trouver un exemple complet.
Conditions préalables
- Vous devez déjà posséder un projet avec des messages de journalisation internationalisés. Voir Section 6.2.2.1, « Créer des messages log internationalisés ».
- Vous devrez connaître le code de projet que vous utilisez. Vous pouvez utiliser un code de projet simple, ou en définir un différent pour chaque interface.
Procédure 6.6. Ajouter les ids et les codes de projets aux messages de journalisation
Indiquer le code de projet de l'interface.
Indiquer le code du projet par l'attribut projectCode de l'annotation@MessageLogger
qui est attachée à une interface de logger personnalisée. Tous les messages définis dans l'interface utiliseront ce code de projet.@MessageLogger(projectCode="ACCNTS") interface AccountsLogger extends BasicLogger { }
Indiquer les ids de messages
Indiquer un id de message pour chaque message qui utilise un attributid
de l'annotation@Message
liée à la méthode qui définit le message.@LogMessage @Message(id=43, value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
10:55:50,638 INFO [com.company.accounts.ejb] (MSC service thread 1-4) ACCNTS000043: Customer query failed, Database not available.
6.2.4.2. Indiquer le niveau de journalisation d'un message
INFO
. Un niveau de journalisation différent peut être indiqué avec l'attribut level
de l'annotation @LogMessage
jointe à la méthode de journalisation.
Procédure 6.7. Indiquer le niveau de journalisation d'un message
Indiquer l'attribut du niveau
Ajouter l'attributlevel
à l'annotation de@LogMessage
de la définition de la méthode de message de journalisation.Allouer un niveau de journalisation
Allouer l'attributlevel
à la valeur du niveau de journalisation de ce message. Les valeurs valides delevel
sont les six constantes énumérées définies dansorg.jboss.logging.Logger.Level
:DEBUG
,ERROR
,FATAL
,INFO
,TRACE
, etWARN
.Import org.jboss.logging.Logger.Level; @LogMessage(level=Level.ERROR) @Message(value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
ERROR
.
10:55:50,638 ERROR [com.company.app.Main] (MSC service thread 1-4) Customer query failed, Database not available.
6.2.4.3. Personnaliser les messages de journalisation par des paramètres
Procédure 6.8. Personnaliser les messages de journalisation avec des paramètres
Ajouter des paramètres à la définition de la méthode
Les paramètres d'un type donné peuvent être ajoutés à la définition de la méthode. Quel que soit le type, la représentation String du paramètre est ce qui est affiché dans le message.Ajouter les références de paramètre dans le message de journalisation
Les références peuvent utiliser des indexations explicites ou ordinaires.- Pour utiliser des indexations ordinaires, insérer les caractères
%s
dans la chaîne de message où vous souhaitez voir apparaître chaque paramètre. Le premier%s
insèrera le premier paramètre, le deuxième insèrera le deuxième paramètre, et ainsi de suite. - Pour les indexations explicites, insérer les caractères
%{#}
dans le message où # correspond au numéro du paramètre que vous souhaitez apercevoir.
Important
@Cause
n'est pas inclus dans le nombre de paramètres.
Exemple 6.1. Paramètres de messages qui utilisent des indexations ordinaires.
@LogMessage(level=Logger.Level.DEBUG) @Message(id=2, value="Customer query failed, customerid:%s, user:%s") void customerLookupFailed(Long customerid, String username);
Exemple 6.2. Paramètres de messages qui utilisent des indexations explicites
@LogMessage(level=Logger.Level.DEBUG) @Message(id=2, value="Customer query failed, customerid:%{1}, user:%{2}") void customerLookupFailed(Long customerid, String username);
6.2.4.4. Indiquer une exception comme cause d'un message de journalisation
Throwable
ou d'une de ses sous-classes et doit être marqué par l'annotation @Cause
. Ce paramètre ne peut pas être référencé dans le message de journal comme les autres paramètres et il s'affiche à la suite du message de journalisation.
@Cause
pour indiquer l'exception "qui cause". On suppose que vous avez déjà créé des messages de journalisation internationalisés auxquels vous souhaitez ajouter cette fonctionnalité.
Procédure 6.9. Indiquer une exception comme cause d'un message de journalisation
Ajouter le paramètre
Ajouter un paramètreThrowable
ou une sous-classe à la méthode.@LogMessage @Message(id=404, value="Loading configuration failed. Config file:%s") void loadConfigFailed(Exception ex, File file);
Ajouter l'annotation
Ajouter l'annotation@Cause
au paramètre.import org.jboss.logging.Cause @LogMessage @Message(value = "Loading configuration failed. Config file: %s") void loadConfigFailed(@Cause Exception ex, File file);
Invoquer la méthode
Quand la méthode est invoquée dans votre code, un objet du type qui convient devra être passé et sera affiché à la suite du message de journalisation.try { confFile=new File(filename); props.load(new FileInputStream(confFile)); } catch(Exception ex) //in case properties file cannot be read { ConfigLogger.LOGGER.loadConfigFailed(ex, filename); }
Vous trouverez ci-dessous la sortie des extraits de code ci-dessus, si le code a lancé une exception de typeFileNotFoundException
.10:50:14,675 INFO [com.company.app.Main] (MSC service thread 1-3) Loading configuration failed. Config file: customised.properties java.io.FileNotFoundException: customised.properties (No such file or directory) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init>(FileInputStream.java:120) at com.company.app.demo.Main.openCustomProperties(Main.java:70) at com.company.app.Main.go(Main.java:53) at com.company.app.Main.main(Main.java:43)
6.2.5. Personnalisation des exceptions internationalisées
6.2.5.1. Ajouter les ids et les codes de projets aux messages d'exceptions
Conidtions préalables
- Vous devrez déjà avoir un projet avec des exceptions internationalisées. Voir Section 6.2.2.3, « Créer des exceptions personnalisées ».
- Vous devrez connaître le code de projet que vous utilisez. Vous pouvez utiliser un code de projet simple, ou en définir un différent pour chaque interface.
Procédure 6.10. Ajouter les ids et les codes de projets aux messages d'exceptions
Indiquer un code de projet
Indiquer le code de projet en utilisant l'attributprojectCode
de l'annotation@MessageBundle
attachée à une interface de lot d'exceptions. Tous les messages qui sont définis dans l'interface utiliseront ce code de projet.@MessageBundle(projectCode="ACCTS") interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); }
Indiquer les ID de messages
Indiquer l'id de message pour chaque exception en utilisant l'attributid
de l'annotation@Message
associée à la méthode qui définit l'exception.@Message(id=143, value = "The config file could not be opened.") IOException configFileAccessError();
Important
Exemple 6.3. Créer des exceptions internationalisées
@MessageBundle(projectCode="ACCTS") interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); @Message(id=143, value = "The config file could not be opened.") IOException configFileAccessError(); }
throw ExceptionBundle.EXCEPTIONS.configFileAccessError();
Exception in thread "main" java.io.IOException: ACCTS000143: The config file could not be opened. at com.company.accounts.Main.openCustomProperties(Main.java:78) at com.company.accounts.Main.go(Main.java:53) at com.company.accounts.Main.main(Main.java:43)
6.2.5.2. Personnaliser les messages d'exception avec des paramètres
Procédure 6.11. Personnaliser les messages d'exception avec les paramètres
Ajouter des paramètres à la définition de la méthode
Les paramètres d'un type donné peuvent être ajoutés à la définition de la méthode. Quel que soit le type, la représentationString
du paramètre est ce qui est affiché dans le message.Ajouter les références de paramètre au message d'exception
Les références peuvent utiliser des indexations explicites ou ordinaires.- Pour utiliser des indexations ordinaires, insérer les caractères
%s
dans la chaîne de message où vous souhaitez voir apparaître chaque paramètre. Le premier%s
insèrera le premier paramètre, le deuxième insèrera le deuxième paramètre, et ainsi de suite. - Pour les indexations explicites, insérer les caractères
%{#}
dans le message où#
correspond au numéro du paramètres que vous souhaitez apercevoir.
L'utilisation des indexations explicites permet aux références de paramètres du message d'être dans un ordre différent que celui défini dans la méthode. C'est important pour les messages traduits qui peuvent nécessiter un ordonnancement des paramètres différent.
Important
@Cause
n'est pas inclus dans le nombre de paramètres.
Exemple 6.4. Utilisation des indexations ordinaires
@Message(id=143, value = "The config file %s could not be opened.") IOException configFileAccessError(File config);
Exemple 6.5. Utilisation des indexations explicites
@Message(id=143, value = "The config file %{1} could not be opened.") IOException configFileAccessError(File config);
6.2.5.3. Indiquer une exception comme cause d'une autre exception
@Cause
. Ce paramètre est utilisé pour passer l'exception de «cause». Ce paramètre ne peut pas être référencé dans le message d'exception.
@Cause
pour indiquer l'exception de « cause ». On suppose que vous avez déjà créé des messages de journalisation internationalisés auxquels vous souhaitez ajouter cette fonctionnalité.
Procédure 6.12. Indiquer une exception comme « cause » d'une autre exception
Ajouter le paramètre
Ajouter un paramètreThrowable
ou une sous-classe à la méthode.@Message(id=328, value = "Error calculating: %s.") ArithmeticException calculationError(Throwable cause, String msg);
Ajouter l'annotation
Ajouter l'annotation@Cause
au paramètre.import org.jboss.logging.Cause @Message(id=328, value = "Error calculating: %s.") ArithmeticException calculationError(@Cause Throwable cause, String msg);
Invoquer la méthode
Invoquer la méthode d'interface pour obtenir un objet d'exception. Le cas d'utilisation le plus commun est de lancer une exception à partir d'un catch block en utilisant l'exception récupérée comme « cause ».try { ... } catch(Exception ex) { throw ExceptionBundle.EXCEPTIONS.calculationError( ex, "calculating payment due per day"); }
Exemple 6.6. Indiquer une exception comme « cause » d'une autre exception
@MessageBundle(projectCode = "TPS") interface CalcExceptionBundle { CalcExceptionBundle EXCEPTIONS = Messages.getBundle(CalcExceptionBundle.class); @Message(id=328, value = "Error calculating: %s.") ArithmeticException calcError(@Cause Throwable cause, String value); }
int totalDue = 5; int daysToPay = 0; int amountPerDay; try { amountPerDay = totalDue/daysToPay; } catch (Exception ex) { throw CalcExceptionBundle.EXCEPTIONS.calcError(ex, "payments per day"); }
Exception in thread "main" java.lang.ArithmeticException: TPS000328: Error calculating: payments per day. at com.company.accounts.Main.go(Main.java:58) at com.company.accounts.Main.main(Main.java:43) Caused by: java.lang.ArithmeticException: / by zero at com.company.accounts.Main.go(Main.java:54) ... 1 more
6.2.6. Référence
6.2.6.1. Configuration Maven JBoss Logging Tools
pom.xml
:
logging-tools
pour obtenir un exemple de fichier pom.xml
complet.
- Le référentiel JBoss Maven Repository doit être activé pour le projet. Voir Section 2.3.2, « Configurer le référentiel JBoss EAP 6 Platform Maven Repository par les paramètres de configuration de Maven ».
- Les dépendances Maven de
jboss-logging
etjboss-logging-processor
doivent être ajoutées. Les deux dépendances sont disponibles sur JBoss EAP 6, ainsi l'élément scope de chaque dépendance peut être définie commeprovided
tel qu'il a été montré.<dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging-processor</artifactId> <version>1.0.0.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.1.0.GA</version> <scope>provided</scope> </dependency>
- Le
maven-compiler-plugin
doit utiliser au minimum la version2.2
et être configuré pour la cible et les sources générées de1.6
.<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin>
6.2.6.2. Format de fichier de propriétés de traduction
key=value
simple, orienté-ligne, décrit dans la documentation pour la classe java.util.Properties
, http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html.
InterfaceName.i18n_locale_COUNTRY_VARIANT.properties
InterfaceName
est le nom de l'interface où les traductions s'appliquent.locale
,COUNTRY
, etVARIANT
identifient les paramètres régionaux correspondant à la traduction.locale
etCOUNTRY
indiquent la langue et le pays en utilisant respectivement les codes Langues et Pays ISO-639 et ISO-3166.COUNTRY
est optionnel.VARIANT
est un identifiant optionnel pouvant être utilisé pour identifier les traductions qui ne s'appliquent qu'à un système d'exploitation ou à un navigateur en particulier.
Exemple 6.7. Échantillon de fichier de propriétés de traductions
GreeterService.i18n_fr_FR_POSIX.properties
.
# Level: Logger.Level.INFO # Message: Hello message sent. logHelloMessageSent=Bonjour message envoyé.
6.2.6.3. Références aux annotations de JBoss Logging Tools
Tableau 6.1. Annotations de JBoss Logging Tools
Annotation | Cible | Description | Attributs |
---|---|---|---|
@MessageBundle | Interface |
Définit l'interface en tant que Lot de Messages
| projectCode |
@MessageLogger | Interface |
Définit l'interface en tant que Message Logger
| projectCode |
@Message | Méthode |
Peut être utilisé dans les Lots de Messages et Message Loggers. Dans un Message Logger, définit une méthode comme étant un logger localisé. Dans un Lot de Messages, définit la méthode comme étant une méthode qui renvoie une Chaîne localisées ou un objet d'Exception.
| value , id |
@LogMessage | Méthode |
Définit une méthode dans un Message Logger comme étant une méthode de logging.
| level (default INFO ) |
@Cause | Paramètre |
Définit un paramètre comme étant un paramètre faisant passer une exception en tant que cause d'un Message Log ou autre exception.
| - |
@Param | Paramètre |
Définit un paramètre comme étant un paramètre passé au constructeur d'une Exception.
| - |
Chapitre 7. Enterprise JavaBeans
7.1. Introduction
7.1.1. Entreprise JavaBeans
7.1.2. Groupe de fonctionnalités EJB 3.1
- Session Beans
- Message Driven Beans
- Vues non-interfaces
- Interfaces locales
- Interfaces distantes
- Services web JAX-WS
- Services web JAX-RS
- Service de minuterie
- Appels asynchrones
- Intercepteurs
- Interopérabilité RMI/IIOP
- Support de transaction
- Sécurité
- API intégrable
- Entity Beans (persistance gérée-bean et conteneur))
- Vues client Entity Beans EJB 2.1
- EJB Query Language (EJB QL)
- Services Web basés JAX-RPC (points de terminaison et vues client)
7.1.3. EJB 3.1 Lite
- ne supportant que les fonctionnalités qui sont utiles pour les applications-web, et
- en permettant aux EJB d'être déployés dans le même fichier WAR sous forme d'application web.
7.1.4. Fonctionnalités EJB 3.1 Lite
- Session Beans sans état, avec état, et singleton
- Interfaces commerciales locales et beans "sans interface"
- Intercepteurs
- Transactions gérées-conteneur et gérées-bean
- Sécurité déclarative et programmatique
- API intégrable
- Interfaces éloignées
- Intéropérabilité RMI-IIOP
- Ponts de terminaison de services web JAX-WS
- Service de minuterie EJB
- Invocations de session beans asynchrones
- Message-driven beans
7.1.5. Beans Enterprise
Important
7.1.6. Écriture des beans Enterprise
7.1.7. Interfaces métier de Session Bean
7.1.7.1. Interfaces de métier Bean Enterprise
7.1.7.2. Interfaces de métier locales EJB
7.1.7.3. Interfaces métier à distance EJB
7.1.7.4. Beans EJB no-interface
7.2. Créer des projets Enterprise Bean
7.2.1. Créer un projet d'archives EJB avec le Red Hat Studio JBoss Developer
Conditions préalables
- Un serveur et un temps d'exécution du serveur ont été établis pour JBoss EAP 6.
Procédure 7.1. Créer un projet EJB dans le Red Hat JBoss Developer Studio
Créer un nouveau projet
Pour ouvrir l'Assistant New EJB Project, naviguer jusqu'au menu Fichier, sélectionner Nouveau puis Projet EJB.Figure 7.1. Assistant New EJB Project
Détails
Fournir les informations suivantes :- Nom du projet.Il s'agira du nom du projet qui apparaît dans Red Hat JBoss Developer Studio, et également le nom du fichier par défaut du fichier JAR déployé.
- Emplacement du projetLe répertoire où les fichiers du projet seront sauvegardés. La valeur par défaut est un répertoire qui se trouve dans l'espace de travail en cours.
- Runtime cible.Il s'agit du runtime de serveur utilisé pour le projet. Il devra être défini au même runtime JBoss EAP 6, qui est utilisé par le serveur dans lequel vous souhaitez déployer.
- Version de module EJB. Il s'agit de la version de la spécification EJB avec laquelle vos beans Enterprise devront se conformer. Red Hat recommande que vous utilisiez
3.1
. - Configuration. Cela vous permet d'ajuster les fonctionnalités prises en charge par votre projet. Utiliser la configuration par défaut pour le runtime que vous avez sélectionné.
Cliquer sur Suivant pour continuer.Java Build Configuration
Cet écran vous permet de personnaliser les répertoires qui contiennent les fichiers source de Java et le répertoire où les résultats de la génération se trouvent.Conservez cette configuration sans y apporter aucun changement et cliquer sur le bouton Suivant.Paramétrage du Module EJB
Cocher la case Generate ejb-jar.xml deployment descriptor (Générer descripteur de déploiement ejb-jar.xml) si un descripteur de déploiement est requis. Le descripteur de déploiement est une option dans EJB 3.1, et peut être rajouté plus tard, si nécessaire.Cliquer sur le bouton Terminé et le projet sera créé. Il s'affichera dans Project Explorer.Figure 7.2. Nouveau projet EJB créé dans Project Explorer
Ajouter l'artifact généré dans le serveur en vue du déploiement
Ouvrir le dialogue Add and Remove en cliquant à droite sur le serveur dans lequel vous souhaitez générer l'artefact dans l'onglet serveur, et sélectionner 'Ajouter et Supprimer'.Sélectionner la ressource à déployer à partir de la colonne Available et cliquer sur le bouton Add. La ressource sera déplacée dans la colonne Configured. Cliquer sur Finish pour fermer le dialogue.Figure 7.3. Ajouter et Supprimer le dialogue
Vous avez maintenant un Projet EJB dans Red Hat JBoss Developer Studio pouvant être construit et déployé pour un serveur spécifique.
7.2.2. Créer un projet EJB Archive dans Maven.
Prérequis :
- Maven est déjà installé.
- Vous comprenez les bases d'utilisation de Maven.
Procédure 7.2. Créer un projet EJB Archive dans Maven
Créer le projet Maven
Un projet EJB peut être créé en utilisant le système archétype de Maven et l'archétypeejb-javaee6
. Pour ce faire, exécuter la commandemvn
avec les paramètres suivants :mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=ejb-javaee6
Maven vous demandera legroupId
, leartifactId
, laversion
et lepackage
de votre projet.[localhost]$ mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=ejb-javaee6 [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Maven Stub Project (No POM) 1 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom >>> [INFO] [INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom <<< [INFO] [INFO] --- maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom --- [INFO] Generating project in Interactive mode [INFO] Archetype [org.codehaus.mojo.archetypes:ejb-javaee6:1.5] found in catalog remote Define value for property 'groupId': : com.shinysparkly Define value for property 'artifactId': : payment-arrangments Define value for property 'version': 1.0-SNAPSHOT: : Define value for property 'package': com.shinysparkly: : Confirm properties configuration: groupId: com.company artifactId: payment-arrangments version: 1.0-SNAPSHOT package: com.company.collections Y: : [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 32.440s [INFO] Finished at: Mon Oct 31 10:11:12 EST 2011 [INFO] Final Memory: 7M/81M [INFO] ------------------------------------------------------------------------ [localhost]$
Ajouter vos beans enterprise
Ecrire vos beans enterprise et les ajouter au projet sous le répertoiresrc/main/java
dans le sous-répertoire approprié pour le paquetage du bean.Créer votre projet
Pour construire ce projet, exécuter la commandemvn package
dans le même répertoire que le fichierpom.xml
. Cela compilera les classes Java et empaquettera le fichier JAR. Le fichier JAR construit se nommeartifactId-version.jar
et se trouve dans le répertoiretarget/
.
7.2.3. Créer un projet EAR contenant un projet EJB
Conditions préalables
- Un serveur et un runtime de serveur pour JBoss EAP 6 a été installé. Veuillez vous référer à Section 1.3.1.5, « Ajouter le serveur de JBoss EAP en utilisant Define New Server ».
Procédure 7.3. Créer un projet EAR contenant un projet EJB
Ouvrir le nouvel Assistant de projet de l'application EAR.
Naviguer vers le menu File, sélectionner New, puis Project et l'assistant New Projet apparaîtra. Sélectionner Java EE/Enterprise Application Project et cliquer sur le bouton Next.Figure 7.4. Nouvel Assistant de Projet de l'Application EAR.
Fournir des Informations
Fournir les informations suivantes :- Nom du projet.Il s'agira du nom du projet qui apparaît dans Red Hat JBoss Developer Studio, et également le nom du fichier par défaut du fichier EAR déployé.
- Emplacement du projetLe répertoire où les fichiers du projet seront sauvegardés. La valeur par défaut est un répertoire qui se trouve dans l'espace de travail en cours.
- Runtime cible.Il s'agit du runtime de serveur utilisé pour le projet. Il devra être défini au même runtime JBoss EAP 6 qui est utilisé par le serveur dans lequel vous souhaitez déployer.
- Version EAR.C'est la version des spécifications de Java Enterprise Edition auquelles votre projet devra se conformer. Red Hat recommande d'utiliser la version
6
. - Configuration. Cela vous permet d'ajuster les fonctionnalités prises en charge par votre projet. Utiliser la configuration par défaut pour le runtime que vous avez sélectionné.
Cliquer sur Suivant pour continuer.Ajouter un nouveau module EJB.
Les nouveaux modules peuvent être ajoutés à partir de la page Enterprise Application de l'assistant. Pour ajouter un nouveau projet EJB en tant que module, veuillez suivre les étapes suivantes :Ajouter un nouveau module EJB.
Cliquer sur New Module, décocher la case Create Default Modules, sélectionner Enterprise Java Bean et cliquer sur Next. L'assistant New EJB Project apparaîtra.Créer un projet EJB.
L'assistant New EJB Project est le même que l'assistant utilisé pour créer de nouveaux projets EJB autonomes et est décrit dans Section 7.2.1, « Créer un projet d'archives EJB avec le Red Hat Studio JBoss Developer ».Les détails minimales requis pour créer le project sont les suivants :- Nom du Projet
- Runtime de la cible
- Version Module EJB
- Configuration
Toutes les autres étapes de l'assistant sont optionnelles. Cliquer sur Finish Terminé) pour finir de créer le projet EJB.
Le projet EJB tout juste créé est listé dans les dépendances du module Java EE et la case est cochée.Optionnel : ajouter un descripteur de déploiement d'application.xml
Cocher la case Generate application.xml deployment descriptor Générer descripteur de déploiement d'application.xmlle cas échéant.Cliquer sur Finish
Deux nouveaux projets vont apparaître, le projet EJB et le projet EAR.Ajouter l'artifact généré dans le serveur en vue du déploiement
Ouvrir la boîte de dialogue Add and Remove (Ajouter et Supprimer) en cliquant avec le bouton droit de la souris, dans l'onglet Servers (Serveurs), sur le serveur dans lequel vous souhaitez déployer l'artéfact de la build dans l'onglet serveur, et sélectionner Add and Remove.Sélectionner la ressource EAR à déployer depuis la colonne Available (disponible) et cliquer sur le bouton Add. La ressource sera déplacée vers la colonne Configured. Cliquer sur Finish pour fermer la boîte de dialogue.Figure 7.5. Ajouter et Supprimer le dialogue
Vous avez maintenant un Projet d'application enterprise avec un Projet EJB membre. Celui-ci se créera et se déploiera vers le serveur indiqué en tant que déploiement EAR unique contenant un sous-déploiement EJB.
7.2.4. Ajouter un descripteur de déploiement à un projet EJB
Conditions préalables :
- Vous avez un projet EJB dans Red Hat JBoss Developer Studio auquel vous souhaitez ajouter un descripteur de déploiement EJB.
Procédure 7.4. Ajouter un descripteur de déploiement à un projet EJB.
Ouvrir le projet
Ouvrir un projet dans Red Hat JBoss Developer Studio.Ajouter un descipteur de déploiement
Cliquer à droite sur le dossier Descripteur de déploiement dans la vue du projet et sélectionner Generate Deployment Descriptor Stub (Générer Descripteur de déploiement).Figure 7.6. Ajouter un descripteur de déploiement
ejb-jar.xml
, sera créé dans ejbModule/META-INF/
. Cliquer deux fois dans le dossier Descripteur de déploiement dans la vue du projet, ce qui permettra d'ouvrir ce fichier également.
7.3. Session Beans
7.3.1. Session Beans
7.3.2. Stateless Session Beans
7.3.3. Stateful Session Beans
7.3.4. Singleton Session Beans
7.3.5. Ajouter des Session Beans à un Projet dans Red Hat JBoss Developer Studio
Conditions préalables :
- Vous avec un EJB ou Dynamic Web Project dans Red Hat JBoss Developer Studio auquel vous souhaitez ajouter un ou plusieurs session beans.
Procédure 7.5. Ajouter des Session Beans à un Projet dans Red Hat JBoss Developer Studio
Ouvrir le projet
Ouvrir un projet dans Red Hat JBoss Developer Studio.Ouvrir l'assistant "Create EJB 3.x Session Bean" (Créer EJB 3.x Session Bean)
Pour ouvrir l'assistant Créer EJB 3.x Session Bean, naviguer dans le menu File, et sélectionner New, puis Session Bean (EJB 3.x).Figure 7.7. Créer un assistant EJB 3.x Session Bean
Indiquer les informations de classe
Fournir les informations suivantes :- ProjetVerifier que le projet qui convient a bien été sélectionné.
- Dossier sourceIl s'agit du dossier dans lequel les fichiers source de Java seront créés. Cela n'a pas normalement besoin d'être changé.
- PackageIndiquer le package auquel cette classe appartient.
- Nom de la classeIndiquer le nom de la classe qui représentera le session bean.
- SuperclassLa classe de session bean peut hériter d'une Superclass. Indiquer ici si votre session a une Superclass.
- Type d'étatIndiquer le type d'état du session bean: stateless, stateful, ou singleton.
- Interfaces commercialesPar défaut, la case No-interface est cochée, donc aucune interface ne sera créée. Cocher les cases des interfaces que vous souhaitez définir et ajuster les noms si nécessaire.Nous vous rappelons que les beans Enterprise d'un WAR (Web Archive) ne supportent qu'EJB 3.1 Lite, et que cela n'inclut pas les interfaces commerciales distantes.
Cliquer sur Next.Informations spécifiques aux Session Bean
Vous pouvez saisir des informations supplémentaires ici pour personnaliser encore plus le session bean. Vous n'avez pas besoin de changer quoi que ce soit ici.Les items que vous pouvez changer sont :- Nom de bean.
- Nom mappé.
- Type de transaction (géré conteneur ou géré bean).
- On peut fournir des interfaces supplémentaires que le bean doit implémenter.
- Vous pouvez également spécifier des interfaces EJB 2.x Home et Component si nécessaire.
Terminer
Cliquer sur le bouton Finish et le nouveau session bean sera créé, et ajouté au projet. Les fichiers de toute nouvelle interface commerciale seront également créés, s'ils ont été spécifiés.

Figure 7.8. Nouveau Session Bean dans Red Hat JBoss Developer Studio
7.4. Message-Driven Beans
7.4.1. Message-Driven Beans
7.4.2. Adaptateurs de ressources
7.4.3. Créer un Message-Driven Bean basé JMS dans Red Hat JBoss Developer Studio
Conditions préalables :
- Vous devrez avoir un projet existant ouvert dans Red Hat JBoss Developer Studio.
- Vous devrez connaître le nom et le type de la destination JMS que le bean écoutera.
- Le support pour JMS (Java Messaging Service) doit être autorisé dans la configuration JBoss EAP 6 dans laquelle ce bean sera déployé.
Procédure 7.6. Ajouter un Message-Driven Bean basé JMS dans Red Hat JBoss Developer Studio
Ouvrir l'assistant Create EJB 3.x Message-Driven Bean
Aller à File → New → Other. Sélectionner EJB/Message-Driven Bean (EJB 3.x) et cliquer sur le bouton Next.Figure 7.9. Créer l'assistant Message-Driven Bean EJB 3.x
Indiquer les détails de la destination de fichier de classe
Il existe trois ensembles de détails à indiquer pour la classe de bean : le projet, la classe Java et le message de destination.- Projet
- Si plusieurs projets existent dans Workspace, veillez à ce que le bon projet soit sélectionné dans le menu Project.
- Le dossier où le fichier source du nouveau bean sera créé est
ejbModule
sous le répertoire du projet sélectionné. Ne peut être changé que pour répondre à des cas particuliers.
- Classe Java
- Les champs obligatoires sont les suivants : Java Package et class name.
- Il n'est pas nécessaire de fournir une Superclass à moins que la logique commerciale de votre application ne l'exige.
- Destination du message
- Voici les informations à fournir pour un Message-Driven Bean basé JMS :
- Destination name. C'est la file d'attente ou le nom du sujet qui contient les messages auxquels le bean répondra.
- La case JMS est sélectionnée par défaut. Veuillez ne pas la changer.
- Définir Destination type comme Queue ou Topic selon ce que l'on vous demande.
Cliquer sur le bouton Next.Saisir les informations spécifiques aux Message-Driven Bean
Les valeurs par défaut sont appropriées pour un Message-Driven Bean basé JMS utilisant des transactions gérées conteneur.- Changer le type de transaction à Bean si le Bean doit utiliser des transactions Bean-managed (gérées bean).
- Changer le nom du Bean s'il est demandé un nom de bean différent du nom de classe.
- L'interface JMS Message Listener sera déjà listée. Vous n'aurez pas besoin d'ajouter ou de supprimer des interfaces, à moins qu'elles soient spécifiques à votre logique commerciale d'applications.
- Laisser les cases décochées pour créer les méthodes stub sélectionnées.
Cliquer sur le bouton Finish.
onMessage()
. Une fenêtre d'édition de Red Hat JBoss Developer Studio est apparue avec le fichier correspondant.
7.4.4. Activer la substitution de propriété des EJB et MDB dans une application
@ActivationConfigProperty
et @Resource
. La substitution de propriétés nécessite la configuration et les changements de code suivants :
- Vous devez activer la substitution de propriété dans le fichier de configuration du serveur JBoss EAP.
- Vous devez définir les propriétés système dans le fichier de configuration du serveur ou les passer comme arguments quand vous démarrez le serveur JBoss EAP.
- Vous devez modifier le code pour utiliser les variables de substitution.
Procédure 7.7. Implémenter la substitution de propriétés dans une application MDB
helloworld-mdb
fourni dans JBoss EAP 6.3 ou version supérieure. Cette section vous montre comment modifier le guide de démarrage rapide pour activer la substitution de propriété.
Configurer le serveur JBoss EAP pour activer la substituion de propriété.
Le serveur JBoss EAP doit être configuré pour activer la substitution de propriété. Pour cela, définir l'attribut<annotation-property-replacement>
qui se trouve dans le sous-systèmeee
du fichier de configuration du serveur àtrue
.- Sauvegarder le fichier de configuration du serveur. L'exemple de guide de démarrage rapide
helloworld-mdb
nécessite un profil complet pour les serveurs autonomes, donc il s'agit dustandalone/configuration/standalone-full.xml
. Si vous exécutez votre serveur dans un domaine géré, il s'agira du fichierdomain/configuration/domain.xml
. - Démarrer le serveur JBos EAP avec le profil complet.Dans Linux :
Dans Windows :EAP_HOME/bin/standalone.sh -c standalone-full.xml
EAP_HOMEbin\standalone.bat -c standalone-full.xml
- Lancer l'interface CLI par la commande pour votre système d'exploitation.Dans Linux :
Dans Windows :EAP_HOME/bin/jboss-cli.sh --connect
EAP_HOME\bin\jboss-cli.bat --connect
- Saisir la commande suivante pour activer la substitution de propriété d'annotation.
/subsystem=ee:write-attribute(name=annotation-property-replacement,value=true)
- Vous devriez voir apparaître le résultat suivant :
{"outcome" => "success"}
- Réviser les changements apportés au fichier de configuration du serveur JBoss EAP. Le sous-système
ee
doit maintenant contenir l'XML suivant.<subsystem xmlns="urn:jboss:domain:ee:1.2"> <spec-descriptor-property-replacement>false</spec-descriptor-property-replacement> <jboss-descriptor-property-replacement>true</jboss-descriptor-property-replacement> <annotation-property-replacement>true</annotation-property-replacement> </subsystem>
Définir les propriétés système.
Vous pouvez spécifier les propriétés du système dans le fichier de configuration du serveur ou vous pouvez les passer comme arguments de ligne de commande lorsque vous démarrez le serveur JBoss EAP. Les propriétés système définies dans le fichier de configuration de serveur ont la priorité sur celles passées sur la ligne de commande lorsque vous démarrez le serveur.- Vous devez définir les propriétés système dans le fichier de configuration.
- Démarrez le serveur JBoss EAP et le Management API comme indiqué dans les étapes précédentes.
- Utiliser la syntaxe de commande suivante pour configurer une propriété système dans le serveur JBoss EAP :
/system-property=PROPERTY_NAME:add(value=PROPERTY_VALUE)
Pour le guide de démarrage rapidehelloworld-mdb
, nous configurons les propriétés système suivantes :/system-property=property.helloworldmdb.queue:add(value=java:/queue/HELLOWORLDMDBPropQueue)
/system-property=property.helloworldmdb.topic:add(value=java:/topic/HELLOWORLDMDBPropTopic)
/system-property=property.connection.factory:add(value=java:/ConnectionFactory)
- Réviser les changements apportés au fichier de configuration du serveur JBoss EAP. Les propriétés système suivantes doivent maintenant apparaître après les
<extensions>
.<system-properties> <property name="property.helloworldmdb.queue" value="java:/queue/HELLOWORLDMDBPropQueue"/> <property name="property.helloworldmdb.topic" value="java:/topic/HELLOWORLDMDBPropTopic"/> <property name="property.connection.factory" value="java:/ConnectionFactory"/> </system-properties>
- Passez les propriétés système comme arguments de ligne de commande quand vous démarrez le serveur JBoss EAP sous la forme d'un
-DPROPERTY_NAME=PROPERTY_VALUE
. Ce qui suit est un exemple de la façon dont on passe les arguments dans les propriétés système définies dans l'étape précédente.EAP_HOME/bin/standalone.sh -c standalone-full.xml -Dproperty.helloworldmdb.queuejava:/queue/HELLOWORLDMDBPropQueue -Dproperty.helloworldmdb.topic=java:/topic/HELLOWORLDMDBPropTopic -Dproperty.connection.factory=java:/ConnectionFactory
Modifier le code pour utiliser les substitutions de propriétés système.
Remplacer les valeurs d'annotation@ActivationConfigProperty
et@Resource
codées en dur par des substitutions pour les propriétés système nouvellement définies. Voici des exemples sur la façon de changer le guide de démarrage rapidehelloworld-mdb
pour qu'il utilise les substitutions de propriétés système nouvellements définies pour les annotations qui se trouvent dans le code source.- Modifier la valeur de propriété
@ActivationConfigProperty
destination
qui se trouve dans la classeHelloWorldQueueMDB
afin d'utiliser la substitution pour la propriété système. L'annotation@MessageDriven
devra ressembler à ceci :@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "${property.helloworldmdb.queue}"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
- Modifier la valeur de propriété
@ActivationConfigProperty
destination
qui se trouve dans la classeHelloWorldTopicMDB
afin d'utiliser la substitution pour la propriété système. L'annotation@MessageDriven
devra ressembler à ceci :@MessageDriven(name = "HelloWorldQTopicMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "${property.helloworldmdb.topic}"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
- Modifier les annotations
@Resource
qui se trouvent dans la classeHelloWorldMDBServletClient
afin d'utiliser les substitutions de propriétés système. Le code devra ressembler à ceci :@Resource(mappedName = "${property.connection.factory}") private ConnectionFactory connectionFactory; @Resource(mappedName = "${property.helloworldmdb.queue}") private Queue queue; @Resource(mappedName = "${property.helloworldmdb.topic}") private Topic topic;
- Modifier le fichier
hornetq-jms.xml
pour pouvoir utiliser les valeurs de substitution de propriétés système.<?xml version="1.0" encoding="UTF-8"?> <messaging-deployment xmlns="urn:jboss:messaging-deployment:1.0"> <hornetq-server> <jms-destinations> <jms-queue name="HELLOWORLDMDBQueue"> <entry name="${property.helloworldmdb.queue}"/> </jms-queue> <jms-topic name="HELLOWORLDMDBTopic"> <entry name="${property.helloworldmdb.topic}"/> </jms-topic> </jms-destinations> </hornetq-server> </messaging-deployment>
- Déployer l'application. L'application utilisera maintenant les valeurs indiquées par les propriétés système comme valeurs de propriété pour
@Resource
et@ActivationConfigProperty
.
7.5. Invoquer les Session Beans
7.5.1. Invoquer un session bean à distance avec JNDI
ejb-remote
contient des projets Maven qui démontrent cette fonctionnalité. Le Quickstart contient des projets à la fois pour le déploiement des session beans et pour le client distant. Les exemples de code ci-dessous sont extraits du projet du client distant.
Conditions préalables
- Vous devez déjà avoir un projet Maven créé, prêt à l'utilisation.
- La configuration du référentiel JBoss EAP 6 Maven a déjà été ajoutée.
- Les session beans que vous souhaitez invoquer sont déjà déployés.
- Les session beans déployés implémentent les interfaces commerciales éloignées.
- Les interfaces commerciales éloignées des beans de session sont disponibles sous forme de dépendance de Maven. Si les interfaces commerciales éloignées ne sont disponibles que sous forme de fichier JAR, alors il est recommandé d'ajouter le JAR à votre référentiel Maven comme un artefact. Reportez-vous à la documentation de Maven pour obtenir des directives
install:install-file
, http://maven.apache.org/plugins/maven-install-plugin/usage.html - Vous aurez besoin de connaître le nom d'hôte et le port JNDI du serveur qui hébergent les session beans.
Procédure 7.8. Ajouter une configuration de projet Maven pour l'invocation à distance des session beans
Ajouter les dépendances de projet utiles
Lepom.xml
du projet doit être mis à jour pour pouvoir inclure les dépendances nécessaires.Ajouter le fichier
jboss-ejb-client.properties
L'API du client JBoss EJB s'attend à trouver un fichier dans le root du projet nomméjboss-ejb-client.properties
qui contient les informations de connexion aux services JNDI. Ajouter ce fichier au répertoiresrc/main/resources/
de votre projet avec le contenu suivant.# In the following line, set SSL_ENABLED to true for SSL remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=default # Uncomment the following line to set SSL_STARTTLS to true for SSL # remote.connection.default.connect.options.org.xnio.Options.SSL_STARTTLS=true remote.connection.default.host=localhost remote.connection.default.port = 4447 remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false # Add any of the following SASL options if required # remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false # remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false # remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS=JBOSS-LOCAL-USER
Changer le nom d'hôte et le port pour qu'ils correspondent au serveur.4447
est le numéro de port par défaut. Pour une connexion sécurisée, définir la ligneSSL_ENABLED
àtrue
et dé-commenter la ligneSSL_STARTTLS
. L'interface éloignée du conteneur supporte les connexions sécurisées et non sécurisées en utilisant le même port.Ajouter des dépendances aux interfaces commerciales à distance.
Ajouter les dépendances Maven aupom.xml
aux interfaces commerciales éloignées des session beans.<dependency> <groupId>org.jboss.as.quickstarts</groupId> <artifactId>jboss-ejb-remote-server-side</artifactId> <type>ejb-client</type> <version>${project.version}</version> </dependency>
Procédure 7.9. Obtenez un Bean Proxy par JNDI et invoquez les méthodes du Bean
Exceptions vérifiées par Handle
Deux des méthodes utilisées dans le code suivant (InitialContext()
etlookup()
) ont une exception vérifiée du typejavax.naming.NamingException
. Ces appels de méthode doivent soit être contenus dans un bloc try/catch qui intercepteNamingException
ou dans une méthode déclarée pour lancerNamingException
. Le Quickstartejb-remote
utilise la seconde technique.Créer un contexte JNDI
Un objet de contexte JNDI fournit le mécanisme pour demander les ressources dans le serveur. Créer un contexte JNDI avec le code suivant :final Hashtable jndiProperties = new Hashtable(); jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); final Context context = new InitialContext(jndiProperties);
Les propriétés de connexion du service JNDI sont lues à partir du fichierjboss-ejb-client.properties
.Utiliser la méthode JNDI Context's lookup() pour obtenir un Bean Proxy
Invoquer le méthodelookup()
du bean proxy et lui faire passer le nom JNDI du session bean dont vous avez besoin. Un objet sera renvoyé et il devra correspondre au type de méthode d'interface commerciale qui contient les méthodes que vous souhaitez invoquer.final RemoteCalculator statelessRemoteCalculator = (RemoteCalculator) context.lookup( "ejb:/jboss-ejb-remote-server-side//CalculatorBean!" + RemoteCalculator.class.getName());
Les noms de session bean JNDI sont définis par une syntaxe particulière. Pour plus d'informations, consulter Section 7.8.1, « Référence de nommage EJB JNDI » .Méthodes d'invocation
Maintenant que vous avez un objet bean proxy, vous pouvez invoquer n'importe quelle méthode qui contient l'interface commerciale distante.int a = 204; int b = 340; System.out.println("Adding " + a + " and " + b + " via the remote stateless calculator deployed on the server"); int sum = statelessRemoteCalculator.add(a, b); System.out.println("Remote calculator returned sum = " + sum);
Le proxy bean transmet la demande d'invocation de méthode au bean de session sur le serveur, où elle est exécutée. Le résultat est retourné au proxy bean qui, ensuite, le retourne à l'appelant. La communication entre le proxy bean et le bean de session distant est transparente à l'appelant.
7.5.2. Contextes Client EJB
- Un client à distance, exécuté comme application Java autonome.
- Un client à distance, exécuté dans une autre instance de JBoss EAP 6.
7.5.3. Considérations lors de l'utilisation d'un Contexte EJB Unique
Vous devez considérer les conditions préalables de votre application lors de l'utilisation d'un contexte client EJB unique avec des clients à distance autonomes. Pour plus d'informations sur les différents types de clients à distance, veuillez consulter : Section 7.5.2, « Contextes Client EJB » .
Un client autonome à distance possède généralement un seul contexte client EJB sauvegardé par n'importe quel nombre de récepteurs EJB. Voici un exemple d'application client à distance autonome :
public class MyApplication { public static void main(String args[]) { final javax.naming.Context ctxOne = new javax.naming.InitialContext(); final MyBeanInterface beanOne = ctxOne.lookup("ejb:app/module/distinct/bean!interface"); beanOne.doSomething(); ... } }
jboss-ejb-client.properties
utilisé pour installer le contexte client EJB et les récepteurs EJB. Cette configuration comprend également les informations de sécurité, qui sont ensuite utilisées pour créer le récepteur EJB qui relie le serveur JBoss EAP 6. Quand le code ci-dessus est invoqué, l'API client EJB recherche le contexte client EJB, ensuite utilisé pour sélectionner le récepteur EJB qui recevra et traitera la requête d'invocation EJB. Dans ce cas, il n'y a que le contexte client EJB unique, donc ce contexte sera utilisé par le code ci-dessus pour invoquer le bean. La procédure pour invoquer un bean de session à distance en utilisant JNDI est décrite plus en détails ici : Section 7.5.1, « Invoquer un session bean à distance avec JNDI » .
Une application d'utilisateur pourrait vouloir invoquer un bean plus d'une fois, mais se connecter au serveur JBoss EAp 6 en utilisant différentes informations de sécurité. Voici un exemple d'une application client à distance autonome qui invoque deux fois le même bean :
public class MyApplication { public static void main(String args[]) { // Use the "foo" security credential connect to the server and invoke this bean instance final javax.naming.Context ctxOne = new javax.naming.InitialContext(); final MyBeanInterface beanOne = ctxOne.lookup("ejb:app/module/distinct/bean!interface"); beanOne.doSomething(); ... // Use the "bar" security credential to connect to the server and invoke this bean instance final javax.naming.Context ctxTwo = new javax.naming.InitialContext(); final MyBeanInterface beanTwo = ctxTwo.lookup("ejb:app/module/distinct/bean!interface"); beanTwo.doSomething(); ... } }
Les contextes client EJB scoped offrent une solution à ce problème. Ils offrent un plus grand contrôle sur les contextes client EJB et leurs contextes JNDI associés, qui sont généralement utilisés pour les invocations EJB. Pour plus d'informations sur les contextes client EJB scoped, veuillez consulter Section 7.5.4, « Utiliser des Contextes Client EJB scoped » et Section 7.5.5, « Configurer les EJB en utilisant un contexte client EJB scoped » .
7.5.4. Utiliser des Contextes Client EJB scoped
Pour invoquer un EJB dans les versions antérieures de JBoss EAP 6, il faut généralement créer un contexte JNDI et lui passer le PROVIDER_URL, qui indique le serveur de cible. Toute invocation faite sur les proxys EJB recherchées en utilisant ce contexte JNDI finiraient sur ce serveur. Dans les contextes client EJB scoped, les applications utilisateur contrôlent quel récepteur EJB est utilisé pour une invocation spécifique.
Avant l'introduction des contextes client EJB étendus, le contexte était généralement étendu à l'application client. Les contextes client étendus autorisent maintenant les contextes client EJB à être étendus avec les contextes JNDI. Voici un exemple d'une application client autonome à distance qui invoque le même bean deux fois en utilisant un contexte client EJB scoped.
public class MyApplication { public static void main(String args[]) { // Use the "foo" security credential connect to the server and invoke this bean instance final Properties ejbClientContextPropsOne = getPropsForEJBClientContextOne(): final javax.naming.Context ctxOne = new javax.naming.InitialContext(ejbClientContextPropsOne); final MyBeanInterface beanOne = ctxOne.lookup("ejb:app/module/distinct/bean!interface"); beanOne.doSomething(); ... ctxOne.close(); // Use the "bar" security credential to connect to the server and invoke this bean instance final Properties ejbClientContextPropsTwo = getPropsForEJBClientContextTwo(): final javax.naming.Context ctxTwo = new javax.naming.InitialContext(ejbClientContextPropsTwo); final MyBeanInterface beanTwo = ctxTwo.lookup("ejb:app/module/distinct/bean!interface"); beanTwo.doSomething(); ... ctxTwo.close(); } }
jboss-ejb-client.properties
. Pour étendre le contexte client EJB au contexte JNDI, il faut également indiquer la propriété org.jboss.ejb.client.scoped.context
et définir sa valeur sur true
. Cette propriété notifie à l'API client EJB qu'il doit créer un contexte client EJB, sauvegardé par des récepteurs EJB, et que le contexte créé doit ensuite être étendu ou visible uniquement au contexte JNDI qui l'a créé. Tout proxy EJB recherché ou invoqué en utilisant ce contexte JNDI ne connaîtra que le contexte client EJB associé à ce contexte JNDI. Les autres contextes JNDI utilisés par l'application pour rechercher ou invoquer des EJB ne reconnaîtra pas les autres contextes client EJB scoped.
org.jboss.ejb.client.scoped.context
et ne sont pas étendus vers un contexte client EJB, utiliseront le comportement par défaut, qui utilise le contexte client EJB existant normalement attaché à l'application dans sa totalité.
Note
InitialContext
lorsqu'il n'est plus utile. Lorsque l'InitialContext
est fermé, les ressources sont libérées immédiatement. Les proxys qui y sont liées ne sont plus valides et tout invocation soulèvera une exception. Une mauvaise fermeture du InitialContext
peut entraîner les problèmes de ressource ou de performance.
7.5.5. Configurer les EJB en utilisant un contexte client EJB scoped
Les EJB peuvent être configurés en utilisant un contexte scoped basé mappe. Cela est possible en complétant une mappe Properties
par programmation en utilisant les propriétés standards trouvées dans jboss-ejb-client.properties
, en indiquant true
pour la propriété org.jboss.ejb.client.scoped.context
, et en passant les propriétés sur la création InitialContext
.
Procédure 7.10. Configurer un EJB en utilisant un contexte scoped basé mappage
Configurer les propriétés
Configurer les propriétés client EJB par programmation, en indiquant le même ensemble de propriétés utilisées dans le fichierjboss-ejb-client.properties
standard. Pour activer le contexte scoped, vous devez indiquer la propriétéorg.jboss.ejb.client.scoped.context
et configurer sa valeur surtrue
. Voici un exemple de configuration des propriétés par programmation :// Configure EJB Client properties for the InitialContext Properties ejbClientContextProps = new Properties(); ejbClientContextProps.put(“remote.connections”,”name1”); ejbClientContextProps.put(“remote.connection.name1.host”,”localhost”); ejbClientContextProps.put(“remote.connection.name1.port”,”4447”); // Property to enable scoped EJB client context which will be tied to the JNDI context ejbClientContextProps.put("org.jboss.ejb.client.scoped.context", “true”);
Passer les propriétés en création de contexte
// Create the context using the configured properties InitialContext ic = new InitialContext(ejbClientContextProps); MySLSB bean = ic.lookup("ejb:myapp/ejb//MySLSBBean!" + MySLSB.class.getName());
- Les contextes générés par les proxys EJB de recherche sont liés par ce contexte étendu et n'utilisent que les paramètres de connexion appropriés. Cela permet de créer différents contextes pour accéder aux données au sein d'une application client ou pour accéder aux serveurs de manière indépendante en utilisant différents logins.
- Dans le client, le
InitialContext
étendu et le proxy étendu sont tous les deux transférés vers les threads, permettant à chaque thread de fonctionner avec le contexte donné. Il est également possible de transférer le proxy vers des threads multiples qui peuvent l'utiliser simultanément. - Le contexte étendu proxy EJB est sérialisé sur l'appel distant, puis désérialisé sur le serveur. Lorsqu'il est désérialisé, les informations de contexte étendu sont supprimées et il retourne à son état par défaut. Si le proxy désérialisé est utilisé sur le serveur distant, c-a-d s'il n'a plus le contexte étendu utilisé lors de sa création, cela peut provoquer une erreur
EJBCLIENT000025
ou éventuellement appeler une cible indésirable en utilisant le nom de l'EJB.
7.5.6. Propriétés Client EJB
Les tableaux suivants énumèrent les propriétés pouvant être configurées par programmation ou dans le fichier jboss-ejb-client.properties
.
Le tableau suivant énumère les propriétés valides pour la bibliothèque entière au sein de la même étendue.
Tableau 7.1. Propriétés globales
Nom de propriété | Description |
---|---|
endpoint.name |
Nom du point de terminaison du client. Si pas configuré, sa valeur par défaut sera
client-endpoint .
Cela peut s'avérer utile pour distinguer différentes configurations de point de terminaison puisque le nom de thread comprend cette propriété.
|
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED |
Valeur booléenne qui indique si le protocole SSL est activé pour toutes les connexions.
|
deployment.node.selector |
Nom complet de l'implémentation de
org.jboss.ejb.client.DeploymentNodeSelector .
Ceci est utilisé pour équilibrer les charges de l'invocation des EJB.
|
invocation.timeout |
Délai pour la liaison EJB ou le cycle requête/réponse de l'invocation de la méthode. Valeur exprimée en millisecondes.
L'invocation de toute méthode lève une
java.util.concurrent.TimeoutException si l'exécution prend plus de temps que la période de délai. L'exécution se termine et le serveur n'est pas interrompu.
|
reconnect.tasks.timeout |
Délai des tâches de reconnexion de l'arrière-plan. Valeur exprimée en millisecondes.
Si des connexions sont éteintes, la prochaine invocation EJB de client utilisera un algorithme pour décider si une reconnexion est nécessaire pour trouver le bon nœud.
|
org.jboss.ejb.client.scoped.context |
Valeur booléenne indiquant s'il faut activer le contexte client EJB scoped. La valeur par défaut est
false .
Si défini comme
true , le client EJB utilisera le contexte étendu (scoped) lié au contexte JNDI. Sinon, le contexte de client EJB utilisera la sélecteur global dans le JVM pour déterminer les propriétés utilisées pour appeler l'hôte et l'EJB à distance.
|
Les propriétés de connexion commencent par le préfixe remote.connection.CONNECTION_NAME
où le CONNECTION_NAME est un identifiant local utilisé uniquement pour identifier la connexion de manière exclusive.
Tableau 7.2. Propriétés de connexion
Nom de propriété | Description |
---|---|
remote.connections |
Liste de
connection-names actifs séparés par des virgules. Chaque connexion est configurée sous ce nom.
|
|
Nom d'hôte ou IP de cette connexion
|
|
Port de la connexion. La valeur par défaut est 4447.
|
|
Nom d'utilisateur utilisé pour authentifier la sécurité de connexion.
|
|
Mot de passe utilisé pour authentifier l'utilisateur.
|
|
Période de délai de la connexion initiale. Après cela, la tâche de reconnexion vérifiera périodiquement si la connexion peut être établie. Valeur exprimée en millisecondes.
|
|
Nom complet de la classe
CallbackHandler . Sera utilisé pour établir la connexion et ne peut être changé tant que la connexion sera ouverte.
|
channel.options.org.jboss.remoting3.RemotingOptions.MAX_OUTBOUND_MESSAGES
|
Valeur entière indiquant le nombre maximale de requêtes sortantes. La valeur par défaut est 80.
Il n'y a qu'une connexion entre le client (JVM) et le serveur pour gérer les invocations.
|
connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS
|
Valeur booléenne déterminant si les identifiants doivent être fournis par le client pour réussir la connexion. La valeur par défaut est
true .
Si défini comme
true , le client doit fournir les identifiants. Si défini comme false , l'invocation est autorisée tant que le connecteur à distance ne demande pas un domaine de sécurité.
|
connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS
|
Désactive certains mécanismes SASL utilisés pour l'authentification pendant la création de la connexion.
JBOSS_LOCAL_USER signifie que le mécanisme d'authentification silencieuse, utilisé lorsque le client et le serveur sont sur la même machine, est désactivé.
|
connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT
|
Valeur booléenne qui active ou désactive l'utilisation de messages de texte brut pendant l'authentification. Si JAAS est utilisé, il doit être défini comme « false » pour autoriser un mot de passe de texte brut.
|
connect.options.org.xnio.Options.SSL_ENABLED
|
Valeur booléenne indiquant si le protocole SSL est activé pour cette connexion.
|
connect.options.org.jboss.remoting3.RemotingOptions.HEARTBEAT_INTERVAL
|
Intervalle pour envoyer une pulsation entre le client et le serveur afin de prévenir les fermetures automatiques, dans le cas d'un pare-feu par exemple. Valeur exprimée en millisecondes.
|
Si la connexion initiale se connecte à un environnement clusterisé, la topologie du cluster est reçue de manière automatique et asynchrone. Ces propriétés sont utilisées pour se connecter à chaque membre reçu. Chaque propriété commence avec le préfixe remote.cluster.CLUSTER_NAME
où le CLUSTER_NAME se réfère à la configuration du sous-système Infinispan du serveur associé.
Tableau 7.3. Propriétés de Cluster
Nom de propriété | Description |
---|---|
clusternode.selector
|
Le nom complet de l'implémentation de
org.jboss.ejb.client.ClusterNodeSelector .
Cette classe, plutôt que
org.jboss.ejb.clientDeploymentNodeSelector , est utilisée pour équilibrer la charge des invocations EJB dans un environnement clusterisé. Si le cluster est complètement arrêté, l'invocation échouera avec comme message No ejb receiver available .
|
channel.options.org.jboss.remoting3.RemotingOptions.MAX_OUTBOUND_MESSAGES
|
Valeur entière indiquant le nombre maximale de requêtes sortantes pouvant être faites au cluster entier.
|
node.NODE_NAME. channel.options.org.jboss.remoting3.RemotingOptions.MAX_OUTBOUND_MESSAGES
|
Valeur entière indiquant le nombre maximale de requêtes sortantes pouvant être faites à ce nœud de cluster spécifique.
|
7.6. Intercepteurs de conteneurs
7.6.1. Intercepteurs de conteneurs
ejb-jar.xml
pour la version 3.1 du descripteur de déploiement ejb-jar.
Les intercepteurs de conteneur configurés pour un EJB sont certains d'être exécutés avant que le JBoss EAP ne fournisse des intercepteurs de sécurité, des intercepteurs de gestion de transaction ou autres intercepteurs fournis par le serveur. Cela permet aux intercepteurs de conteneurs spécifiques à l'application de traiter ou de configurer des données de contexte pertinentes avant l'invocation.
Bien que les intercepteurs de conteneur soient modélisés pour pouvoir ressembler aux intercepteurs de Java EE, il y a quelques différences dans la sémantique de l'API. Par exemple, il est illégal pour les intercepteurs de conteneur d'invoquer la méthode javax.interceptor.InvocationContext.getTarget()
parce que ces intercepteurs sont invoqués bien avant que les composants EJB ne soient configurés ou instanciés.
7.6.2. Créer une classe d'intercepteur de conteneur
Les classes d'intercepteur de conteneur sont de simples POJO (Plain Old Java Objects). Ils utilisent @javax.annotation.AroundInvoke
pour marquer la méthode qui est invoquée lors de l'invocation du bean.
iAmAround
de l'invocation :
Exemple 7.1. Exemple de classe d'intercepteur de conteneur
public class ClassLevelContainerInterceptor { @AroundInvoke private Object iAmAround(final InvocationContext invocationContext) throws Exception { return this.getClass().getName() + " " + invocationContext.proceed(); } }
jboss-ejb3.xml
décrit ici : Section 7.6.3, « Configurer un intercepteur de conteneur ».
7.6.3. Configurer un intercepteur de conteneur
Les intercepteurs de conteneurs utilisent les bibliothèques d'intercepteur J2EE standard, ce qui signifie qu'ils utilisent les mêmes éléments XSD que ceux qui sont autorisés dans le fichier ejb-jar.xml
pour la version 3.1 du descripteur de déploiement ejb-jar. Comme ils se reposent sur les bibliothèques standard d'interceptor Jave EE, les intercepteurs de conteneur peuvent uniquement être configurés à l'aide de descripteurs de déploiement. Cela a été conçu pour que les applications n'exigent pas une annotation spécifique de JBoss ou autre dépendance de bibliothèque. Pour plus d'informations sur les intercepteurs de conteneur, voir : Section 7.6.1, « Intercepteurs de conteneurs ».
Procédure 7.11. Créer le fichier de descripteur pour configurer l'intercepteur de conteneur
- Créer un fichier
jboss-ejb3.xml
dans le répertoireMETA-INF
du déploiement EJB. - Configurer les éléments de l'intercepteur du conteneur dans le fichier du descripteur.
- Utiliser l'espace-nom
urn:container-interceptors:1.0
pour indiquer la configuration des éléments de l'intercepteur du conteneur. - Utiliser l'élément
<container-interceptors>
pour indiquer les intercepteurs du conteneur. - Utiliser les éléments
<interceptor-binding>
pour relier l'intercepteur du conteneur aux EJB. Les intercepteurs peuvent être reliés d'une des manières suivantes :- Relier l'intercepteur à tous les EJB du déploiement par le caractère générique
*
. - Relier l'intercepteur au niveau bean individuel par le nom spécifique de l'EJB.
- Relier l'intercepteur au niveau de méthode spécifique des EJB.
Note
Ces éléments sont configurés par EJB 3.1 XSD de la même façon que pour les intercepteurs Java EE.
- Vérifier les exemples d'éléments ci-dessus dans le fichier de descripteur suivant.
Exemple 7.2. jboss-ejb3.xml
<jboss xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:jee="http://java.sun.com/xml/ns/javaee" xmlns:ci ="urn:container-interceptors:1.0"> <jee:assembly-descriptor> <ci:container-interceptors> <!-- Default interceptor --> <jee:interceptor-binding> <ejb-name>*</ejb-name> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class> </jee:interceptor-binding> <!-- Class level container-interceptor --> <jee:interceptor-binding> <ejb-name>AnotherFlowTrackingBean</ejb-name> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class> </jee:interceptor-binding> <!-- Method specific container-interceptor --> <jee:interceptor-binding> <ejb-name>AnotherFlowTrackingBean</ejb-name> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class> <method> <method-name>echoWithMethodSpecificContainerInterceptor</method-name> </method> </jee:interceptor-binding> <!-- container interceptors in a specific order --> <jee:interceptor-binding> <ejb-name>AnotherFlowTrackingBean</ejb-name> <interceptor-order> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class> </interceptor-order> <method> <method-name>echoInSpecificOrderOfContainerInterceptors</method-name> </method> </jee:interceptor-binding> </ci:container-interceptors> </jee:assembly-descriptor> </jboss>
L'XSD de l'espace-nomurn:container-interceptors:1.0
se trouve dansEAP_HOME/docs/schema/jboss-ejb-container-interceptors_1_0.xsd
.
7.6.4. Modifier l'identité du contexte de sécurité
Par défaut, lorsque vous effectuez un appel distant à un EJB déployé sur le serveur d'applications, la connexion au serveur est authentifiée et toute demande reçue via cette connexion sera exécutée en tant qu'identité ayant authentifié la connexion. Cela est vrai pour les appels client-serveur et serveur-serveur. Si vous avez besoin d'utiliser différentes identités en provenance d'un même client, vous devrez normalement ouvrir des connexions multiples au serveur afin que chacune d'entre elles soient authentifiée en tant qu'identité différente. Plutôt que d'ouvrir plusieurs connexions de client, vous pouvez donner l'autorisation à l'utilisateur authentifié d'exécuter une requête sous un nom différent.
ejb-security-interceptors
pour obtenir un exemple complet.
Procédure 7.12. Modifier l'identité du contexte de sécurité
Créer l'intercepteur côté client
Cet intercepteur côté client doit implémenter l'interfaceorg.jboss.ejb.client.EJBClientInterceptor
. L'intercepteur doit passer l'identité requise par le mappage de données contextuelles, par l'intermédiaire d'un appelEJBClientInvocationContext.getContextData()
. Voici un exemple de code d'intercepteur côté client :public class ClientSecurityInterceptor implements EJBClientInterceptor { public void handleInvocation(EJBClientInvocationContext context) throws Exception { Principal currentPrincipal = SecurityActions.securityContextGetPrincipal(); if (currentPrincipal != null) { Map<String, Object> contextData = context.getContextData(); contextData.put(ServerSecurityInterceptor.DELEGATED_USER_KEY, currentPrincipal.getName()); } context.sendRequest(); } public Object handleInvocationResult(EJBClientInvocationContext context) throws Exception { return context.getResult(); } }
Les applications utilisateur peuvent insérer l'intercepteur dans la chaîne d'intercepteur dans leEJBClientContext
par l'un des moyens suivants :Par programmation
Par cette approche, vous appelez la méthodeorg.jboss.ejb.client.EJBClientContext.registerInterceptor(int order, EJBClientInterceptor interceptor)
et passez l'instanceorder
et l'instanceinterceptor
. L'instanceorder
est utilisé pour déterminer où exactement cet intercepteur est placé dans la chaîne d'intercepteur.Mécanisme ServiceLoader
Cette approche nécessite la création d'un fichierMETA-INF/services/org.jboss.ejb.client.EJBClientInterceptor
et de le placer ou le mettre dans le chemin de classe de l'application client. Les règles du fichier sont dictées par le Java ServiceLoader Mechanism. Ce fichier doit contenir, dans chaque ligne distincte, le nom de classe qualifié complet de l'implémentation d'intercepteur de client EJB. Les classes d'intercepteur de client EJB doivent être disponibles dans le chemin de classe. Les intercepteurs de client EJB ajoutés en utilisant le mécanisme deServiceLoader
sont ajoutés à la fin de la chaîne d'intercepteur de client, dans l'ordre dans lequel ils se trouvent dans le chemin de classe (classpath). Le démarrage rapide ou quickstartejb-security-interceptors
utilise cette approche.
Créer et configurer l'intercepteur du conteneur côté serveur
Les classes d'intercepteur de conteneur sont de simples Plain Old Java Objects (POJOs). Elles utilisent@javax.annotation.AroundInvoke
pour marquer la méthode qui sera invoquée lors de l'invocation sur le bean. Pour plus d'informations sur les intercepteurs de conteneur, consulter : Section 7.6.1, « Intercepteurs de conteneurs ».Créer l'intercepteur de conteneur
Cet intercepteur reçoit leInvocationContext
en même temps que l'identité et demande le changement d'identité nouvelle. Ce qui suit est une version modifiée de l'exemple de code :public class ServerSecurityInterceptor { private static final Logger logger = Logger.getLogger(ServerSecurityInterceptor.class); static final String DELEGATED_USER_KEY = ServerSecurityInterceptor.class.getName() + ".DelegationUser"; @AroundInvoke public Object aroundInvoke(final InvocationContext invocationContext) throws Exception { Principal desiredUser = null; UserPrincipal connectionUser = null; Map<String, Object> contextData = invocationContext.getContextData(); if (contextData.containsKey(DELEGATED_USER_KEY)) { desiredUser = new SimplePrincipal((String) contextData.get(DELEGATED_USER_KEY)); Collection<Principal> connectionPrincipals = SecurityActions.getConnectionPrincipals(); if (connectionPrincipals != null) { for (Principal current : connectionPrincipals) { if (current instanceof UserPrincipal) { connectionUser = (UserPrincipal) current; break; } } } else { throw new IllegalStateException("Delegation user requested but no user on connection found."); } } ContextStateCache stateCache = null; try { if (desiredUser != null && connectionUser != null && (desiredUser.getName().equals(connectionUser.getName()) == false)) { // The final part of this check is to verify that the change does actually indicate a change in user. try { // We have been requested to use an authentication token // so now we attempt the switch. stateCache = SecurityActions.pushIdentity(desiredUser, new OuterUserCredential(connectionUser)); } catch (Exception e) { logger.error("Failed to switch security context for user", e); // Don't propagate the exception stacktrace back to the client for security reasons throw new EJBAccessException("Unable to attempt switching of user."); } } return invocationContext.proceed(); } finally { // switch back to original context if (stateCache != null) { SecurityActions.popIdentity(stateCache);; } } }
Configurer l'intercepteur du conteneur
Pour plus d'informations sur la façon de configurer les intercepteurs de conteneurs côté serveur, consulter : Section 7.6.3, « Configurer un intercepteur de conteneur ».
Créer le JAAS LoginModule
Ce composant doit vérifier que l'utilisateur est en mesure d'exécuter les requêtes selon l'identité de la requête. Les exemples de code abrégés suivants indiquent les méthodes de login et de validation :@SuppressWarnings("unchecked") @Override public boolean login() throws LoginException { if (super.login() == true) { log.debug("super.login()==true"); return true; } // Time to see if this is a delegation request. NameCallback ncb = new NameCallback("Username:"); ObjectCallback ocb = new ObjectCallback("Password:"); try { callbackHandler.handle(new Callback[] { ncb, ocb }); } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } return false; // If the CallbackHandler can not handle the required callbacks then no chance. } String name = ncb.getName(); Object credential = ocb.getCredential(); if (credential instanceof OuterUserCredential) { // This credential type will only be seen for a delegation request, if not seen then the request is not for us. if (delegationAcceptable(name, (OuterUserCredential) credential)) { identity = new SimplePrincipal(name); if (getUseFirstPass()) { String userName = identity.getName(); if (log.isDebugEnabled()) log.debug("Storing username '" + userName + "' and empty password"); // Add the username and an empty password to the shared state map sharedState.put("javax.security.auth.login.name", identity); sharedState.put("javax.security.auth.login.password", ""); } loginOk = true; return true; } } return false; // Attempted login but not successful. } protected boolean delegationAcceptable(String requestedUser, OuterUserCredential connectionUser) { if (delegationMappings == null) { return false; } String[] allowedMappings = loadPropertyValue(connectionUser.getName(), connectionUser.getRealm()); if (allowedMappings.length == 1 && "*".equals(allowedMappings[1])) { // A wild card mapping was found. return true; } for (String current : allowedMappings) { if (requestedUser.equals(current)) { return true; } } return false; }
ejb-security-interceptors
README
pour obtenir des instructions complètes et des informations détaillées sur le code.
7.6.5. Sécurité supplémentaire pour l'authentification EJB
Par défaut, lorsque vous effectuez un appel distant à un EJB déployé sur le serveur d'applications, la connexion au serveur est authentifiée et toute demande reçue via cette connexion est exécutée en utilisant les informations d'identification qui ont authentifié la connexion. L'authentification au niveau de la connexion dépend des capacités des mécanismes sous-jacents SASL (Simple Authentication and Security Layer). Plutôt que d'écrire des mécanismes SASL personnalisés, vous pouvez ouvrir et authentifier une connexion au serveur, puis ajouter les jetons de sécurité supplémentaires avant d'appeler un EJB. Cette rubrique décrit comment passer des informations supplémentaires sur la connexion existante du client pour l'authentification de l'EJB.
Procédure 7.13. Information de sécurité pour l'authentification EJB
Créer l'intercepteur côté client
Cet intercepteur doit implémenterorg.jboss.ejb.client.EJBClientInterceptor
. L'intercepteur doit passer le token de sécurité supplémentaire par le mappage de données contextuelles, par l'intermédiaire d'un appelEJBClientInvocationContext.getContextData()
. Voici un exemple de code d'intercepteur côté client qui crée un token de sécurité supplémentaire :public class ClientSecurityInterceptor implements EJBClientInterceptor { public void handleInvocation(EJBClientInvocationContext context) throws Exception { Principal currentPrincipal = SecurityActions.securityContextGetPrincipal(); if (currentPrincipal != null) { Map<String, Object> contextData = context.getContextData(); contextData.put(ServerSecurityInterceptor.DELEGATED_USER_KEY, currentPrincipal.getName()); } context.sendRequest(); } public Object handleInvocationResult(EJBClientInvocationContext context) throws Exception { return context.getResult(); } }
Pour obtenir des informations sur la façon de connecter l'intercepteur client dans une application, voir Section 7.6.6, « Utiliser un intercepteur côté client dans une application ».Créer et configurer l'intercepteur du conteneur côté serveur
Les classes d'intercepteur de conteneur sont de simples Plain Old Java Objects (POJOs). Elles utilisent@javax.annotation.AroundInvoke
pour marquer la méthode qui est invoquée lors de l'invocation sur le bean. Pour plus d'informations sur les intercepteurs de conteneur, consulter : Section 7.6.1, « Intercepteurs de conteneurs ».Créer l'intercepteur de conteneur
Cet intercepteur récupère le jeton d'authentification de sécurité du contexte et le passe au domaine JAAS (Java Authentication and Autorisation Service) pour vérification. Voici un exemple de code d'intercepteur de conteneur :public class ServerSecurityInterceptor { private static final Logger logger = Logger.getLogger(ServerSecurityInterceptor.class); static final String DELEGATED_USER_KEY = ServerSecurityInterceptor.class.getName() + ".DelegationUser"; @AroundInvoke public Object aroundInvoke(final InvocationContext invocationContext) throws Exception { Principal desiredUser = null; UserPrincipal connectionUser = null; Map<String, Object> contextData = invocationContext.getContextData(); if (contextData.containsKey(DELEGATED_USER_KEY)) { desiredUser = new SimplePrincipal((String) contextData.get(DELEGATED_USER_KEY)); Collection<Principal> connectionPrincipals = SecurityActions.getConnectionPrincipals(); if (connectionPrincipals != null) { for (Principal current : connectionPrincipals) { if (current instanceof UserPrincipal) { connectionUser = (UserPrincipal) current; break; } } } else { throw new IllegalStateException("Delegation user requested but no user on connection found."); } } ContextStateCache stateCache = null; try { if (desiredUser != null && connectionUser != null && (desiredUser.getName().equals(connectionUser.getName()) == false)) { // The final part of this check is to verify that the change does actually indicate a change in user. try { // We have been requested to use an authentication token // so now we attempt the switch. stateCache = SecurityActions.pushIdentity(desiredUser, new OuterUserCredential(connectionUser)); } catch (Exception e) { logger.error("Failed to switch security context for user", e); // Don't propagate the exception stacktrace back to the client for security reasons throw new EJBAccessException("Unable to attempt switching of user."); } } return invocationContext.proceed(); } finally { // switch back to original context if (stateCache != null) { SecurityActions.popIdentity(stateCache);; } } }
Configurer l'intercepteur du conteneur
Pour plus d'informations sur la façon de configurer les intercepteurs de conteneurs côté serveur, consulter : Section 7.6.3, « Configurer un intercepteur de conteneur ».
Créer le JAAS LoginModule
Ce module personnalisé exécute l'authentification à l'aide de l'information de la connexion authentifiée existante ainsi qu'à l'aide qu'un jeton de sécurité supplémentaire. Voici un exemple de code réduit qui utilise le jeton de sécurité supplémentaire et qui exécute l'authentification. On peut trouver l'exemple de code complet dans le quickstartejb-security-interceptors
fourni dans JBoss EAP 6.3 ou version supérieure.public class DelegationLoginModule extends AbstractServerLoginModule { private static final String DELEGATION_PROPERTIES = "delegationProperties"; private static final String DEFAULT_DELEGATION_PROPERTIES = "delegation-mapping.properties"; private Properties delegationMappings; private Principal identity; @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { addValidOptions(new String[] { DELEGATION_PROPERTIES }); super.initialize(subject, callbackHandler, sharedState, options); String propertiesName; if (options.containsKey(DELEGATION_PROPERTIES)) { propertiesName = (String) options.get(DELEGATION_PROPERTIES); } else { propertiesName = DEFAULT_DELEGATION_PROPERTIES; } try { delegationMappings = loadProperties(propertiesName); } catch (IOException e) { throw new IllegalArgumentException(String.format("Unable to load properties '%s'", propertiesName), e); } } @SuppressWarnings("unchecked") @Override public boolean login() throws LoginException { if (super.login() == true) { log.debug("super.login()==true"); return true; } // Time to see if this is a delegation request. NameCallback ncb = new NameCallback("Username:"); ObjectCallback ocb = new ObjectCallback("Password:"); try { callbackHandler.handle(new Callback[] { ncb, ocb }); } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } return false; // If the CallbackHandler can not handle the required callbacks then no chance. } String name = ncb.getName(); Object credential = ocb.getCredential(); if (credential instanceof OuterUserCredential) { // This credential type will only be seen for a delegation request, if not seen then the request is not for us. if (delegationAcceptable(name, (OuterUserCredential) credential)) { identity = new SimplePrincipal(name); if (getUseFirstPass()) { String userName = identity.getName(); if (log.isDebugEnabled()) log.debug("Storing username '" + userName + "' and empty password"); // Add the username and an empty password to the shared state map sharedState.put("javax.security.auth.login.name", identity); sharedState.put("javax.security.auth.login.password", ""); } loginOk = true; return true; } } return false; // Attempted login but not successful. }
Ajouter le LoginModule personnalisé à la chaîne
Vous devez ajouter le nouveau LoginModule personnalisé à l'endroit qui convient dans la chaîne pour qu'il soit invoqué dans le bon ordre. Dans cet exemple, leSaslPlusLoginModule
doit être mis dans la chaîne avant le LoginModule qui charge les rôles par l'optionpassword-stacking
.Configurer l'ordonnancement du LoginModule par le Management CLI
Ce qui suit est un exemple de commandes de Management CLI qui enchaînent leSaslPlusLoginModule
personnalisé avant que le LoginModuleRealmDirect
définisse l'optionpassword-stacking
./subsystem=security/security-domain=quickstart-domain:add(cache-type=default)
/subsystem=security/security-domain=quickstart-domain/authentication=classic:add
/subsystem=security/security-domain=quickstart-domain/authentication=classic/login-module=DelegationLoginModule:add(code=org.jboss.as.quickstarts.ejb_security_plus.SaslPlusLoginModule,flag=optional,module-options={password-stacking=useFirstPass})
/subsystem=security/security-domain=quickstart-domain/authentication=classic/login-module=RealmDirect:add(code=RealmDirect,flag=required,module-options={password-stacking=useFirstPass})
Configurer l'ordonnancement du LoginModule manuellement
Ce qui suit est un exemple de XML qui configure l'ordonnancement du LoginModule dans le sous-système desecurity
du fichier de configuration du serveur. LeSaslPlusLoginModule
doit précéder le LoginModuleRealmDirect
pour qu'il puisse vérifier l'utilisateur distant avant que les rôles utilisateurs ne soient chargés et l'optionpassword-stacking
définie.<security-domain name="quickstart-domain" cache-type="default"> <authentication> <login-module code="org.jboss.as.quickstarts.ejb_security_plus.SaslPlusLoginModule" flag="required"> <module-option name="password-stacking" value="useFirstPass"/> </login-module> <login-module code="RealmDirect" flag="required"> <module-option name="password-stacking" value="useFirstPass"/> </login-module> </authentication> </security-domain>
Créer le client distant
Dans l'exemple de code suivant, on assume que le fichieradditional-secret.properties
auquel accède le JAAS LoginModule ci-dessus contient la propriété suivante :quickstartUser=7f5cc521-5061-4a5b-b814-bdc37f021acc
Le code suivant montre comment créer un token de sécurité et comment le définir avant l'appel EJB. Le token secret est codé en dur dans des buts de démonstration uniquement. Ce client se contente d'afficher les résultats sur la console.import static org.jboss.as.quickstarts.ejb_security_plus.EJBUtil.lookupSecuredEJB; public class RemoteClient { /** * @param args */ public static void main(String[] args) throws Exception { SimplePrincipal principal = new SimplePrincipal("quickstartUser"); Object credential = new PasswordPlusCredential("quickstartPwd1!".toCharArray(), "7f5cc521-5061-4a5b-b814-bdc37f021acc"); SecurityActions.securityContextSetPrincipalCredential(principal, credential); SecuredEJBRemote secured = lookupSecuredEJB(); System.out.println(secured.getPrincipalInformation()); } }
7.6.6. Utiliser un intercepteur côté client dans une application
Vous pouvez connecter un intercepteur côté client dans une application par programmation ou en utilisant un mécanisme ServiceLoader. La procédure suivante décrit les deux méthodes.
Procédure 7.14. Connecter l'intercepteur
Par programmation
Par cette approche, vous appelez l'APIorg.jboss.ejb.client.EJBClientContext.registerInterceptor(int order, EJBClientInterceptor interceptor)
et passez l'instanceorder
et l'instanceinterceptor
. L'instanceorder
est utilisée pour déterminer où exactement cetinterceptor
est placé dans la chaîne d'intercepteur du client.Mécanisme ServiceLoader
Cette approche nécessite la création d'un fichierMETA-INF/services/org.jboss.ejb.client.EJBClientInterceptor
et le placer ou le mettre dans le chemin de classe de l'application client. Les règles du fichier sont dictées par le Java ServiceLoader Mechanism. Ce fichier devrait contenir, dans chaque ligne distincte, le nom de classe qualifié complet de l'implémentation d'intercepteur de client EJB. Les classes d'intercepteur de client EJB doivent être disponibles dans le chemin de classe. Les intercepteurs de client EJB ajoutés en utilisant le mécanisme deServiceLoader
sont ajoutés à la fin de la chaîne d'intercepteur de client, dans l'ordre dans lequel ils se trouvent dans le chemin de classe (classpath). Le démarrage rapide ou quickstartejb-security-interceptors
utilise cette approche.
7.7. JavaBeans Enterprise clusterisés
7.7.1. JavaBeans clusterisées (EJB)
Note
7.7.2. Configuration de client EJB In-server ou Autonome
jboss-ejb-client.properties
pour un client EJB autonome, ou même le fichier jboss-ejb-client.xml
pour une application côté serveur doit être étendue pour inclure une configuration de cluster.
jboss-ejb-client.xml
) montre la configuration complète :
Exemple 7.3. Client autonome avec configuration jboss-ejb-client.properties
remote.clusters=ejb remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false remote.cluster.ejb.username=test remote.cluster.ejb.password=password
jboss-ejb-client.xml
et ajouter la configuration de cluster comme illustré dans l'exemple suivant :
Exemple 7.4. Application client déployée dans une autre instance EAP 6 (Configurer le fichier jboss-ejb-client.xml)
<jboss-ejb-client xmlns:xsi="urn:jboss:ejb-client:1.2" xsi:noNamespaceSchemaLocation="jboss-ejb-client_1_2.xsd"> <client-context> <ejb-receivers> <!-- this is the connection to access the app-one --> <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-1" /> <!-- this is the connection to access the app-two --> <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-2" /> </ejb-receivers> <!-- if an outbound connection connects to a cluster; a list of members is provided after successful connection. To connect to this node this cluster element must be defined. --> <clusters> <!-- cluster of remote-ejb-connection-1 --> <cluster name="ejb" security-realm="ejb-security-realm-1" username="quickuser1"> <connection-creation-options> <property name="org.xnio.Options.SSL_ENABLED" value="false" /> <property name="org.xnio.Options.SASL_POLICY_NOANONYMOUS" value="false" /> </connection-creation-options> </cluster> </clusters> </client-context> </jboss-ejb-client>
Note
7.7.3. Mettre en place une politique d'équilibrage des charges presonnalisée pour les appels EJB
AllClusterNodeSelector
pour les appels EJB. Le comportement de sélection de noeud de AllClusterNodeSelector
ressemble à celui du sélecteur par défaut, sauf que AllClusterNodeSelector
utilise tous les noeuds de cluster disponibles, même pour les clusters de grande taille (nombre de noeuds>20). Si un noeud de cluster non connecté est renvoyé, il s'ouvre automatiquement. L'exemple suivant montre une implémentation de AllClusterNodeSelector
:
package org.jboss.as.quickstarts.ejb.clients.selector; import java.util.Arrays; import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.ejb.client.ClusterNodeSelector; public class AllClusterNodeSelector implements ClusterNodeSelector { private static final Logger LOGGER = Logger.getLogger(AllClusterNodeSelector.class.getName()); @Override public String selectNode(final String clusterName, final String[] connectedNodes, final String[] availableNodes) { if(LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("INSTANCE "+this+ " : cluster:"+clusterName+" connected:"+Arrays.deepToString(connectedNodes)+" available:"+Arrays.deepToString(availableNodes)); } if (availableNodes.length == 1) { return availableNodes[0]; } final Random random = new Random(); final int randomSelection = random.nextInt(availableNodes.length); return availableNodes[randomSelection]; } }Vous pouvez également implémenter le
SimpleLoadFactorNodeSelector
pour les appels EJB. L'équilibrage des charges dans SimpleLoadFactorNodeSelector
a lieu sur la base d'un facteur de charge. Le facteur de charge (2/3/4) est calculé sur la base des noms de noeuds (A/B/C) irrespectivement de la charge qui pèse sur chaque noeud. L'exemple suivant vous montre une implémentation de SimpleLoadFactorNodeSelector
:
package org.jboss.as.quickstarts.ejb.clients.selector; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.ejb.client.DeploymentNodeSelector; public class SimpleLoadFactorNodeSelector implements DeploymentNodeSelector { private static final Logger LOGGER = Logger.getLogger(SimpleLoadFactorNodeSelector.class.getName()); private final Map<String, List<String>[]> nodes = new HashMap<String, List<String>[]>(); private final Map<String, Integer> cursor = new HashMap<String, Integer>(); private ArrayList<String> calculateNodes(Collection<String> eligibleNodes) { ArrayList<String> nodeList = new ArrayList<String>(); for (String string : eligibleNodes) { if(string.contains("A") || string.contains("2")) { nodeList.add(string); nodeList.add(string); } else if(string.contains("B") || string.contains("3")) { nodeList.add(string); nodeList.add(string); nodeList.add(string); } else if(string.contains("C") || string.contains("4")) { nodeList.add(string); nodeList.add(string); nodeList.add(string); nodeList.add(string); } } return nodeList; } @SuppressWarnings("unchecked") private void checkNodeNames(String[] eligibleNodes, String key) { if(!nodes.containsKey(key) || nodes.get(key)[0].size() != eligibleNodes.length || !nodes.get(key)[0].containsAll(Arrays.asList(eligibleNodes))) { // must be synchronized as the client might call it concurrent synchronized (nodes) { if(!nodes.containsKey(key) || nodes.get(key)[0].size() != eligibleNodes.length || !nodes.get(key)[0].containsAll(Arrays.asList(eligibleNodes))) { ArrayList<String> nodeList = new ArrayList<String>(); nodeList.addAll(Arrays.asList(eligibleNodes)); nodes.put(key, new List[] { nodeList, calculateNodes(nodeList) }); } } } } private synchronized String nextNode(String key) { Integer c = cursor.get(key); List<String> nodeList = nodes.get(key)[1]; if(c == null || c >= nodeList.size()) { c = Integer.valueOf(0); } String node = nodeList.get(c); cursor.put(key, Integer.valueOf(c + 1)); return node; } @Override public String selectNode(String[] eligibleNodes, String appName, String moduleName, String distinctName) { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("INSTANCE " + this + " : nodes:" + Arrays.deepToString(eligibleNodes) + " appName:" + appName + " moduleName:" + moduleName + " distinctName:" + distinctName); } // if there is only one there is no sense to choice if (eligibleNodes.length == 1) { return eligibleNodes[0]; } final String key = appName + "|" + moduleName + "|" + distinctName; checkNodeNames(eligibleNodes, key); return nextNode(key); } }
jboss-ejb-client.properties
Vous devrez ajouter la propriété remote.cluster.ejb.clusternode.selector
au nom de votre classe d'implémentation (AllClusterNodeSelector
ou SimpleLoadFactorNodeSelector
). Le sélecteur vérifiera les serveurs configurés disponibles au moment de l'invocation. l'exemple suivant utilise AllClusterNodeSelector
comme sélecteur de noeud de déploiement :
remote.clusters=ejb remote.cluster.ejb.clusternode.selector=org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false remote.cluster.ejb.username=test remote.cluster.ejb.password=password remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=one,two remote.connection.one.host=localhost remote.connection.one.port = 4447 remote.connection.one.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false remote.connection.one.username=user remote.connection.one.password=user123 remote.connection.two.host=localhost remote.connection.two.port = 4547 remote.connection.two.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
Vous devrez ajouter la propriété remote.cluster.ejb.clusternode.selector
à la liste de constructeur PropertiesBasedEJBClientConfiguration
. L'exemple suivant utilise AllClusterNodeSelector
comme sélecteur de noeud de déploiement :
Properties p = new Properties(); p.put("remote.clusters", "ejb"); p.put("remote.cluster.ejb.clusternode.selector", "org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector"); p.put("remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false"); p.put("remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED", "false"); p.put("remote.cluster.ejb.username", "test"); p.put("remote.cluster.ejb.password", "password"); p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false"); p.put("remote.connections", "one,two"); p.put("remote.connection.one.port", "4447"); p.put("remote.connection.one.host", "localhost"); p.put("remote.connection.two.port", "4547"); p.put("remote.connection.two.host", "localhost"); EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p); ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc); EJBClientContext.setSelector(selector); p = new Properties(); p.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); InitialContext context = new InitialContext(p);
jboss-ejb-client.xml
Pour pouvoir utiliser la politique d'équilibrage des charges pour la communication d'un serveur à un autre, empaquetez la classe avec l'application et configurez-là dans les paramètres de jboss-ejb-client.xml
(qui se trouvent dans le dossier META-INF
). L'exemple suivant utilise AllClusterNodeSelector
comme sélecteur de noeud de déploiement :
<jboss-ejb-client xmlns:xsi="urn:jboss:ejb-client:1.2" xsi:noNamespaceSchemaLocation="jboss-ejb-client_1_2.xsd"> <client-context> <ejb-receivers> <!-- this is the connection to access the app --> <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-1" /> </ejb-receivers> <!-- if an outbound connection connect to a cluster a list of members is provided after successful connection. To connect to this node this cluster element must be defined. --> <clusters> <!-- cluster of remote-ejb-connection-1 --> <cluster name="ejb" security-realm="ejb-security-realm-1" username="test" cluster-node-selector="org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector"> <connection-creation-options> <property name="org.xnio.Options.SSL_ENABLED" value="false" /> <property name="org.xnio.Options.SASL_POLICY_NOANONYMOUS" value="false" /> </connection-creation-options> </cluster> </clusters> </client-context> </jboss-ejb-client>Pour pouvoir utiliser la configuration ci-dessus en toute sécurité, il vous faudra ajouter
ejb-security-realm-1
à la configuration côté serveur. L'exemple suivant vous montre les commandes CLI pour ajouter un domaine de sécurité (ejb-security-realm-1
). La valeur correspond au mot de passe base64 codifié pour l'utilisateur "test" :
core-service=management/security-realm=ejb-security-realm-1:add() core-service=management/security-realm=ejb-security-realm-1/server-identity=secret:add(value=cXVpY2sxMjMr)
Note
-Djboss.node.name=
ou le fichier de configuration du serveur standalone.xml
pour configurer le nom du serveur (server name=""). Veillez à ce que le nom de serveur soit unique. En mode de domaine, le contrôleur valide automatiquement le fait que les noms soient uniques.
7.7.4. Comportement de transaction des invocations EJB
Les attributs de transaction d'applications distribuées EAP doivent être gérés comme si l'application était appelée sur le même serveur. Pour mettre fin à une transaction, la méthode de destination doit comporter la mention REQUIRES_NEW
, à l'aide d'interfaces différentes.
Note
Pour invoquer les beans de session EJB avec un client EAP 6 autonome, le client doit avoir une référence à l'objet InitialContext
tandis que les proxies EJB ou UserTransaction
sont utilisés. Il est également important de garder l'objet InitialContext
ouvert tant que les proxies EJB ou UserTransaction
sont utilisés. Le contrôle des connexions se fera à l'intérieur des classes créées par InitialContext
avec les propriétés.
InitialContext
:
package org.jboss.as.quickstarts.ejb.multi.server; import java.util.Date; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import javax.naming.Context; import javax.naming.InitialContext; import org.jboss.as.quickstarts.ejb.multi.server.app.MainApp; import org.jboss.ejb.client.ContextSelector; import org.jboss.ejb.client.EJBClientConfiguration; import org.jboss.ejb.client.EJBClientContext; import org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration; import org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector; public class Client { /** * @param args no args needed * @throws Exception */ public static void main(String[] args) throws Exception { // suppress output of client messages Logger.getLogger("org.jboss").setLevel(Level.OFF); Logger.getLogger("org.xnio").setLevel(Level.OFF); Properties p = new Properties(); p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false"); p.put("remote.connections", "one"); p.put("remote.connection.one.port", "4447"); p.put("remote.connection.one.host", "localhost"); p.put("remote.connection.one.username", "quickuser"); p.put("remote.connection.one.password", "quick-123"); EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p); ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc); EJBClientContext.setSelector(selector); Properties props = new Properties(); props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); InitialContext context = new InitialContext(props); final String rcal = "ejb:jboss-ejb-multi-server-app-main/ejb//" + ("MainAppBean") + "!" + MainApp.class.getName(); final MainApp remote = (MainApp) context.lookup(rcal); final String result = remote.invokeAll("Client call at "+new Date()); System.out.println("InvokeAll succeed: "+result); } }
Note
UserTransaction
sur un client n'est pas prise en charge pour les scénarios de contextes client EJB scoped et pour les invocations qui utilisent le protocole remote-naming
. C'est parce que dans ces scénarios, InitialContext
encapsule sa propre instance de contexte client, à laquelle on ne peut pas accéder par les méthodes statiques de la classe EJBClient
. Quand la méthode EJBClient.getUserTransaction()
est invoquée, elle renvoie une transaction en provenance du contexte client EJB (global) par défaut (pas forcément initialisé) et non pas en provenance du contexte souhaité.
L'exemple suivant vous montre comment obtenir une référence UserTransaction
sur un client autonome :
import org.jboss.ejb.client.EJBClient; import javax.transaction.UserTransaction; . . Context context=null; UserTransaction tx=null; try { Properties props = new Properties(); // REMEMBER: there must be a jboss-ejb-client.properties with the connection parameter // in the clients classpath props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); context = new InitialContext(props); System.out.println("\n\tGot initial Context: "+context); tx=EJBClient.getUserTransaction("yourServerName"); System.out.println("UserTransaction = "+tx.getStatus()); tx.begin(); // do some work ... }catch (Exception e) { e.printStackTrace(); tx.rollback(); }finally{ if(context != null) { context.close(); } }
Note
UserTransaction
côté client, démarrer votre serveur avec la propriété système suivante -Djboss.node.name=yourServerName
et utilisez-là ensuite côté client comme suit :
tx=EJBClient.getUserTransaction("yourServerName");Remplacer "yourServerName" par le nom de votre serveur. Si une transaction utilisateur démarre sur un nœud, toutes les invocations seront sticky sur le nœud et le nœud devra avoir tous les EJB nécessaires. Il n'est pas possible d'utiliser
UserTransaction
avec un protocole de nommage à distance ou avec un scoped-context.
7.8. Référence
7.8.1. Référence de nommage EJB JNDI
ejb:<appName>/<moduleName>/<distinctName>/<beanName>!<viewClassName>?stateful
<appName>
- Si le fichier JAR du session bean a été déployé dans un EAR, alors ce se sera le nom de l'EAR. Par défaut, le nom d'un EAR correspond à son nom de fichier sans le suffixe
.ear
. Le nom de l'application peut également être remplacé dans son fichierapplication.xml
. Si le bean de session n'est pas déployé dans un EAR, laissez le vide. <moduleName>
- Le nom du module correspond au nom du fichier dans lequel le session bean est déployé. Par défaut, le nom du fichier JAR correspond à son nom de fichier sans le suffixe
.jar
. Le nom du module peut également être remplacé par leejb-jar.xml
du JAR. <distinctName>
- JBoss EAP 6 permet à chaque déploiement de spécifier un nom distinct en option. Si le déploiement n'a pas de nom distinct, laisser le vide.
<beanName>
- Le nom du bean est le nom de classe de la session bean à invoquer.
<viewClassName>
- Le nom de classe de vue est le nom de classe complet de l'interface distante de l'interface distante. Inclut le nom du package de l'interface.
?stateful
- Le suffixe
?stateful
est requis quand le nom JNDI se réfère à un bean de session stateful. Non inclus dans d'autres types de bean.
7.8.2. Résolution de référence EJB
@EJB
et @Resource
. Veuillez noter qu'XML remplace toujours les annotations, mais que les mêmes règles s'appliquent.
Règles pour les annotations @EJB
- L'annotation
@EJB
possède également un attributmappedName()
. La spécification le considère comme une métadonnée spécifique au fournisseur tandis que JBoss reconnaitmappedName()
en tant que nom JNDI global du EJB que vous référencez. Si vous avez indiqué unmappedName()
, alors tous les autres attributs seront ignorés et ce nom JNDI global sera utilisé comme liaison. - Si vous indiquez
@EJB
sans attributs définis :@EJB ProcessPayment myEjbref;
Alors les règles suivantes vont s'appliquer :- Le jar EJB du bean de référencement est analysé pour trouver un EJB avec l'interface utilisée dans l'injection
@EJB
. S'il existe plus d'un EJB qui publie la même interface commerciale, alors une exception apparaîtra. S'il n'y a qu'un seul bean dans cette interface, alors celui-là sera utilisé. - Chercher l'EAR des EJB qui publient cette interface. S'il y a des doubles, alors il y aura une exception. Sinon le bean correspondant sera renvoyé.
- Chercher globalement dans le runtime de JBoss un EJB de cette interface. Une fois de plus, s'il y a des doubles, il y aura une exception.
@EJB.beanName()
correspond à<ejb-link>
. Si lebeanName()
est défini, il vous faudra utiliser le même algorithme que@EJB
sans attribut défini mis à partbeanName()
comme une clé de la recherche. Il existe une exception à cette règle si vous utilisez la syntaxe ejb-link '#'. La syntaxe '#' vous permettra de mettre un chemin d'accès relatif dans un jar de l'EJB qui contient l'EJB de référencement. Reportez-vous à la spécification EJB 3.1 pour plus de détails.
7.8.3. Dépendances de projet pour les clients EJB distants
Tableau 7.4. Dépendances Maven pour les clients EJB
GroupID | ArtifactID |
---|---|
org.jboss.spec | jboss-javaee-6.0 |
org.jboss.as | jboss-as-ejb-client-bom |
org.jboss.spec.javax.transaction | jboss-transaction-api_1.1_spec |
org.jboss.spec.javax.ejb | jboss-ejb-api_3.1_spec |
org.jboss | jboss-ejb-client |
org.jboss.xnio | xnio-api |
org.jboss.xnio | xnio-nio |
org.jboss.remoting3 | jboss-remoting |
org.jboss.sasl | jboss-sasl |
org.jboss.marshalling | jboss-marshalling-river |
jboss-javaee-6.0
et jboss-as-ejb-client-bom
, ces dépendances doivent être ajoutées à la section <dependencies>
du fichier pom.xml
.
jboss-javaee-6.0
et jboss-as-ejb-client-bom
doivent être ajoutées à la section <dependencyManagement>
du fichier pom.xml
avec le scope d' import
.
Note
artifactID
peuvent être modifiées. Veuillez consulter le référentiel Maven pour connaître la version la plus récente.
<dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>3.0.0.Final-redhat-1</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.jboss.as</groupId> <artifactId>jboss-as-ejb-client-bom</artifactId> <version>7.1.1.Final-redhat-1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
ejb-remote/client/pom.xml
dans les fichiers quickstart pour obtenir un exemple complet de configuration de dépendance pour une invocation de session bean éloignée.
7.8.4. Référence de descripteur de déploiement jboss-ejb3.xml
jboss-ejb3.xml
est un descripteur de déploiement personnalisé pouvant être utilisé dans un JAR EJB ou des archives WAR. Dans une archive JAR EJB, il doit être situé dans le répertoire META-INF/
. Dans une archive WAR, il doit être situé dans le répertoire WEB-INF/
.
ejb-jar.xml
, qui utilise les mêmes espace-noms et qui fournit des espace-noms supplémentaires. Les contenus de jboss-ejb3.xml
sont mergés avec les contenus de ejb-jar.xml
, et les items jboss-ejb3.xml
ont la priorité.
jboss-ejb3.xml
. Voir http://java.sun.com/xml/ns/javaee/ pour la documentation sur les espace-noms standard.
http://www.jboss.com/xml/ns/javaee
.
Espace-nom de descripteur d'assemblage
<assembly-descriptor>
. Ils peuvent être utilisés pour appliquer leur configuration à un simple bean, ou à tous les beans du déploiement en utilisant \*
comme ejb-name
.
- Espace-nom de clustering :
urn:clustering:1.0
xmlns:c="urn:clustering:1.0"
Cela vous permet de marquer les EJB comme étant clusterisés. Il s'agit du descripteur de déploiement équivalent au@org.jboss.ejb3.annotation.Clustered
.<c:clustering> <ejb-name>DDBasedClusteredSFSB</ejb-name> <c:clustered>true</c:clustered> </c:clustering>
- L'espace-nom de sécurité (
urn:security
) xmlns:s="urn:security"
Cela vous permet de définir le domaine de sécurité et le principal prétendant pour l'EJB.<s:security> <ejb-name>*</ejb-name> <s:security-domain>myDomain</s:security-domain> <s:run-as-principal>myPrincipal</s:run-as-principal> </s:security>
- L'espace-nom d'adaptateur de ressource :
urn:resource-adapter-binding
xmlns:r="urn:resource-adapter-binding"
Cela vous permet de définir l'adaptateur de ressource d'un Message-Driven Bean.<r:resource-adapter-binding> <ejb-name>*</ejb-name> <r:resource-adapter-name>myResourceAdapter</r:resource-adapter-name> </r:resource-adapter-binding>
- L'espace-nom IIOP :
urn:iiop
xmlns:u="urn:iiop"
L'espace-nom IIOP est l'endroit où les paramètres IIOP sont configurés.- L'espace-nom du pool :
urn:ejb-pool:1.0
xmlns:p="urn:ejb-pool:1.0"
Cela vous permet de sélectionner le pool qui est utilisé par les stateless session beans ou par les Message-Driven Beans. Les pools sont définis dans la configuration du serveur.<p:pool> <ejb-name>*</ejb-name> <p:bean-instance-pool-ref>my-pool</p:bean-instance-pool-ref> </p:pool>
- L'espace-nom du cache :
urn:ejb-cache:1.0
xmlns:c="urn:ejb-cache:1.0"
Cela vous permet de sélectionner le cache qui est utilisé par les stateful session beans inclus. Les caches sont définis dans la configuration du serveur.<c:cache> <ejb-name>*</ejb-name> <c:cache-ref>my-cache</c:cache-ref> </c:cache>
Exemple 7.5. Fichier exemple de jboss-ejb3.xml
<?xml version="1.1" encoding="UTF-8"?> <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="urn:clustering:1.0" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" version="3.1" impl-version="2.0"> <enterprise-beans> <message-driven> <ejb-name>ReplyingMDB</ejb-name> <ejb-class>org.jboss.as.test.integration.ejb.mdb.messagedestination.ReplyingMDB</ejb-class> <activation-config> <activation-config-property> <activation-config-property-name>destination</activation-config-property-name> <activation-config-property-value>java:jboss/mdbtest/messageDestinationQueue </activation-config-property-value> </activation-config-property> </activation-config> </message-driven> </enterprise-beans> <assembly-descriptor> <c:clustering> <ejb-name>DDBasedClusteredSFSB</ejb-name> <c:clustered>true</c:clustered> </c:clustering> </assembly-descriptor> </jboss:ejb-jar>
Chapitre 8. Les services JBoss MBean
8.1. Rédiger des services JBoss MBean
crée
, quand il démarre
, s'arrête
ou se détruit
lui-même.
- Si vous souhaitez que des méthodes spécifiques soient invoquées sur votre MBean, il vous faudra déclarer ces méthodes dans votre interface MBean. Cette approche permet à votre implementation MBean d'éviter des dépendances sur les classes JBoss.
- Si vous ne vous inquiétez pas des dépendances sur les classes spécifiques à JBoss, alors vous souhaiterez sans doute que votre interface MBean prolonge l'interface
ServiceMBean
et la classeServiceMBeanSupport
. La classeServiceMBeanSupport
fournit des implémentations des méthodes de cycle de vie de services commecreate
,start
etstop
. Pour un événement spécifique commestart()
, vous devrez surcharger la méthodestartService()
donnée par la classe ServiceMBeanSupport.
8.2. Exemple de MBean standard
.sar
).
ConfigServiceMBean
déclare des méthodes spécifiques telles que les méthodes start
, getTimeout
et stop
pour qu'elles démarrent
, mettent en attente
et stoppent
le MBean correctement sans utiliser de classes spécifiques à JBoss. La classe ConfigService
implémente l'interface ConfigServiceMBean
et de ce fait implémente les méthodes utilisées dans cette interface.
PlainThread
étend la classe ServiceMBeanSupport
et implémente l'interface PlainThreadMBean
. PlainThread
démarre un thread et utilise la méthode ConfigServiceMBean.getTimeout()
pour déterminer la durée pendant laquelle le thread doit dormir.
Exemple 8.1. Exemples de services MBean
package org.jboss.example.mbean.support; public interface ConfigServiceMBean { int getTimeout(); void start(); void stop(); } package org.jboss.example.mbean.support; public class ConfigService implements ConfigServiceMBean { int timeout; @Override public int getTimeout() { return timeout; } @Override public void start() { //Create a random number between 3000 and 6000 milliseconds timeout = (int)Math.round(Math.random() * 3000) + 3000; System.out.println("Random timeout set to " + timeout + " seconds"); } @Override public void stop() { timeout = 0; } } package org.jboss.example.mbean.support; import org.jboss.system.ServiceMBean; public interface PlainThreadMBean extends ServiceMBean { void setConfigService(ConfigServiceMBean configServiceMBean); } package org.jboss.example.mbean.support; import org.jboss.system.ServiceMBeanSupport; public class PlainThread extends ServiceMBeanSupport implements PlainThreadMBean { private ConfigServiceMBean configService; private Thread thread; private volatile boolean done; @Override public void setConfigService(ConfigServiceMBean configService) { this.configService = configService; } @Override protected void startService() throws Exception { System.out.println("Starting Plain Thread MBean"); done = false; thread = new Thread(new Runnable() { @Override public void run() { try { while (!done) { System.out.println("Sleeping...."); Thread.sleep(configService.getTimeout()); System.out.println("Slept!"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); thread.start(); } @Override protected void stopService() throws Exception { System.out.println("Stopping Plain Thread MBean"); done = true; } }
jboss-service.xml
montre comment la classe ConfigService
est injectée dans la classe PlainThread
en utilisant la balise inject
. La balise inject
établit une dépendance entre PlainThreadMBean
et ConfigServiceMBean
permettant ainsi à PlainThreadMBean
d'utiliser ConfigServiceMBean
aisément.
Exemple 8.2. Décripteur de service JBoss-service.xml
<server xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:service:7.0 jboss-service_7_0.xsd" xmlns="urn:jboss:service:7.0"> <mbean code="org.jboss.example.mbean.support.ConfigService" name="jboss.support:name=ConfigBean"/> <mbean code="org.jboss.example.mbean.support.PlainThread" name="jboss.support:name=ThreadBean"> <attribute name="configService"> <inject bean="jboss.support:name=ConfigBean"/> </attribute> </mbean> </server>
jboss-service.xml
dans le dossier META-INF
d'une archive de service (.sar
).
8.3. Déployer JBoss MBean Services
ServiceMBeanTest.sar
) en mode Domain
, utliser les commandes suivantes :
[domain@localhost:9999 /] deploy ~/Desktop/ServiceMBeanTest.sar
[domain@localhost:9999 /] deploy ~/Desktop/ServiceMBeanTest.sar --all-server-groups
ServiceMBeanTest.sar
) en mode Standalone
, utliser la commande suivante :
[standalone@localhost:9999 /] deploy ~/Desktop/ServiceMBeanTest.sar
[standalone@localhost:9999 /] undeploy ServiceMBeanTest.sar
Chapitre 9. Clustering dans les applications web
9.1. Réplique de session
9.1.1. La réplique de session HTTP
9.1.2. Cache de session web
standalone-ha.xml
, ou les profils de domaine gérés ha
ou full-ha
. Les éléments les plus couramment configurés sont le mode cache et le nombre de propriétaires de cache pour un cache distribué.
Le mode cache peut être REPL
(par défaut) ou DIST
.
- REPL
- Le mode
REPL
reproduit tout le cache à un nœud sur deux dans le cluster. Cela constitue l'option la plus sûre, mais elle introduit aussi plus de surcharge de temps. - DIST
- Le mode
DIST
est semblable au buddy mode fourni dans les exécutions précédentes. Il réduit la surcharge de temps en répartissant le cache entre le nombre de nœuds indiqués dans le paramètreowners
. Ce nombre de propriétaires est défini par défaut à2
.
Le paramètre owners
contrôle combien de nœuds de clusters détiennent des duplicatas de la session. La valeur par défaut est 2
.
9.1.3. Configurer le cache de session web
REPL
. Si vous souhaitez utiliser le mode DIST
, exécutez les deux commandes suivantes dans 'interface CLI. Si vous utilisez un profil différent, changez le nom de profil dans les commandes. Si vous utilisez un serveur autonome, retirez la partie /profile=ha
des commandes.
Procédure 9.1. Configurer le cache de session web
Modifier le mode cache par défaut en
DIST
./profile=ha/subsystem=infinispan/cache-container=web/:write-attribute(name=default-cache,value=dist)
Définir le nombre de propriétaires de cache distribué.
La commande suivante définit5
propriétaires. La valeur par défaut est2
./profile=ha/subsystem=infinispan/cache-container=web/distributed-cache=dist/:write-attribute(name=owners,value=5)
Modifier le mode cache par défaut en
REPL
./profile=ha/subsystem=infinispan/cache-container=web/:write-attribute(name=default-cache,value=repl)
Relancer le serveur
Après avoir modifié le mode cache du web, vous devez relancer le serveur.
Votre serveur est configuré pour une copie de session. Pour utiliser une copie de session dans vos propres applications, veuillez vous référer au sujet suivant : Section 9.1.4, « Activer la copie de session pour votre application ».
9.1.4. Activer la copie de session pour votre application
Pour profiter des fonctionnalités HA (High Availability) de JBoss EAP 6, configurer votre application de manière à ce qu'elle soit distribuable. Cette procédure vous montrera comment y parvenir puis vous expliquera certaines options de configuration avancées que vous pourrez utiliser.
Procédure 9.2. Rendez votre Application Distribuable
Prérequis : indiquer que votre application est distribuable
Si votre application n'apparaît pas comme distribuable, ses sessions ne seront jamais distribuées. Ajouter l'élément<distributable />
dans la balise<web-app>
du fichier descriptifweb.xml
de votre application. Voici un exemple :Exemple 9.1. Configuration minimum pour une application distribuable
<?xml version="1.0"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <distributable/> </web-app>
Modifier le comportement de réplication par défaut si vous le souhaitez.
Si vous souhaitez changer une des valeurs qui affectent la réplique de session, vous pouvez les changer dans l'élément<replication-config>
qui est un dépendant de l'élément enfant de l'élément<jboss-web>
du fichierjboss-web.xml
de votre application. Pour un exemple donné, ne l'inclure que si vous souhaitez remplacer les valeurs par défaut. L'exemple suivant énumère tous les paramètres par défaut, et est suivi d'un tableau qui explique les options les plus fréquemment modifées.Exemple 9.2. Valeurs
<replication-config>
par défaut<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 5.0//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd"> <jboss-web> <replication-config> <cache-name>custom-session-cache</cache-name> <replication-trigger>SET</replication-trigger> <replication-granularity>ATTRIBUTE</replication-granularity> <use-jk>false</use-jk> <max-unreplicated-interval>30</max-unreplicated-interval> <snapshot-mode>INSTANT</snapshot-mode> <snapshot-interval>1000</snapshot-interval> <session-notification-policy>com.example.CustomSessionNotificationPolicy</session-notification-policy> </replication-config> </jboss-web>
Tableau 9.1. Options communes pour la réplique de session
Option
|
Description
|
---|---|
<replication-trigger>
|
Contrôle quelles conditions doivent déclencher la réplication de données de session dans l'ensemble du cluster. Cette option est utile, quand un objet mutable stocké comme attribut de session est accessible à partir de la session, le conteneur n'a aucun moyen évident de savoir si l'objet a été modifié et s'il doit être reproduit, sauf si la méthode
setAttribute() est appelée directement.
Valeurs valides pour
Quelle que soit la configuration, vous pourrez toujours déclencher la réplication de session en appelant
setAttribute() .
|
<replication-granularity>
|
Détermine la granularité des données répliquées. La valeur par défaut est
SESSION , mais peut être définie à ATTRIBUTE à la place, pour augmenter la performance dans les sessions où la plupart des attributs restent inchangés.
|
Tableau 9.2. Options les moins communément modifiées pour les réplications de session
Option
|
Description
|
---|---|
<useJK>
|
Présumons qu'un équilibreur de charge tel que
mod_cluster , mod_jk , ou mod_proxy soit utilisé. La valeur par défaut est false . Si définie sur true , le conteneur examine l'ID de session associé à chaque requête et remplace la partie jvmRoute de l'ID de session en cas de basculement.
|
<max-unreplicated-interval>
|
Le plus grand intervalle (en secondes) à attendre après une session avant de déclencher une réplication d'un horodateur de session, même s'il est considéré comme inchangé. Cela permet aux nœuds de cluster d'être informés de l'horodateur de chaque session et aux sessions non répliquées de ne pas expirer de manière incorrecte pendant un basculement. Cela vous permet également de vous fier à une valeur correcte pour les appels à méthode
HttpSession.getLastAccessedTime() pendant un basculement.
Par défaut, aucune valeur n'est indiquée. Cela signifie que la configuration
jvmRoute du conteneur détermine si le basculement JK est utilisé. Une valeur 0 entraîne une réplication de l'horodateur à chaque accès à la session. Une valeur -1 n'entraîne une réplication de l'horodateur que si une autre activité entraîne une réplication pendant la requête. Une valeur positive supérieure à HttpSession.getMaxInactiveInterval() est traitée comme une erreur de configuration et sera convertie à 0 .
|
<snapshot-mode>
|
Indique quand les sessions sont répliquées vers d'autres nœuds. La valeur par défaut est
INSTANT et l'autre valeur possible est INTERVAL .
En mode
INSTANT , les modifications sont répliquées à la fin d'une requête, au moyen du thread de traitement des requêtes. L'option <snapshot-interval> est ignorée.
En mode
INTERVAL , une tâche d'arrière-plan s'exécute à l'intervalle indiqué par <snapshot-interval> , et réplique les sessions modifiées.
|
<snapshot-interval>
|
L'intervalle, en millisecondes, pendant lequel les sessions modifiées doivent être répliquées si elles utilisent
INTERVAL pour la valeur de <snapshot-mode> .
|
<session-notification-policy>
|
Nom complet de la classe de l'implémentation de l'interface
ClusteredSessionNotificationPolicy qui contrôle si les notifications de spécification servlet sont émises vers un HttpSessionListener , HttpSessionAttributeListener , ou HttpSessionBindingListener enregistré.
|
9.2. Passivation et activation HttpSession
9.2.1. La passivation et l'activation de session HTTP
- Quand le conteneur réclame la création d'une nouvelle session, si le nombre de sessions actives en cours dépasse une limite configurable, le serveur tentera de passiver certaines sessions pour faire place à une nouvelle session.
- De façon périodique, à un intervalle précis configuré, une tâche d'arrière-plan vérifiera si les sessions doivent être passivées.
- Quand une application web est déployée et qu'une copie de sauvegarde de sessions actives sur d'autres serveurs est acquise par le gestionnaire de session de l'application web récemment déployée, les sessions peuvent être passivées.
- La session n'a pas été utilisée pendant une durée plus longue qu'une période d'inactivité configurable maximale.
- Le nombre de sessions actives dépasse un maximum configurable et la session n'a pas été utilisée pendant une durée plus longue qu'une période d'inactivité configurable maximale.
9.2.2. Configurer la passivation HttpSession dans votre application
La passivation HttpSession est configurée dans le fichier WEB_INF/jboss-web.xml
ou META_INF/jboss-web.xml
de votre application.
Exemple 9.3. Exemple de fichier jboss-web.xml
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 5.0//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd"> <jboss-web version="6.0" xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_6_0.xsd"> <max-active-sessions>20</max-active-sessions> <passivation-config> <use-session-passivation>true</use-session-passivation> <passivation-min-idle-time>60</passivation-min-idle-time> <passivation-max-idle-time>600</passivation-max-idle-time> </passivation-config> </jboss-web>
Éléments de configuration de passivation
<max-active-sessions>
- Nombre maximal de sessions actives autorisé. Si le nombre de sessions gérées par le gestionnaire de sessions dépasse cette valeur et que la passivation est activée, ce dépassement sera passivé sur la base du
<passivation-min-idle-time>
configuré. Ensuite, si le nombre de sessions actives dépasse toujours cette limite, les tentatives de création de nouvelles sessions échoueront. La valeur par défaut de-1
ne définit aucune limite quant au nombre maximal de sessions actives. <passivation-config>
- Cet élément contient le reste des paramètres de configuration de passivation, en tant qu'éléments enfants.
Eléments enfants <passivation-config>
<use-session-passivation>
- Indique si oui ou non la passivation de session doit être utilisée. La valeur par défaut est
false
. <passivation-min-idle-time>
- La durée minimum, en secondes, pendant laquelle une session doit être inactive avant que le conteneur n'envisage de la passiver de manière à réduire le nombre de sessions actives pour être conforme à la valeur définie par les max-active-sessions. La valeur par défaut
-1
empêche les sessions d'être passivées avant que le temps de<passivation-max-idle-time>
ne se soit écoulé. Les valeurs -1 ou supérieures sont déconseillées si<max-active-sessions>
est configuré. <passivation-max-idle-time>
- La durée maximum, en secondes, pendant laquelle une session peut être inactive avant que le conteneur ne tente de la passiver pour économiser de la mémoire. La passivation de ces sessions aura lieu, que le nombre de sessions actives excède
<max-active-sessions>
ou pas. Cette valeur doit être inférieure à la configuration<session-timeout>
dans le fichierweb.xml
. La valeur par défaut-1
désactive la passivation selon l'inactivité maximum.
Note
<max-active-sessions>
. Le nombre de sessions répliquées à partir d'autres nœuds dépend aussi de savoir si le mode cache REPL
ou DIST
est désactivé. Dans le mode cache REPL
, chaque session est répliquée vers chaque nœud. Dans le mode cache DIST
, chaque session n'est répliquée que vers le nombre de nœuds indiqué par le paramètre owner
. Veuillez vous référer à Section 9.1.2, « Cache de session web » et Section 9.1.3, « Configurer le cache de session web » pour plus de renseignements sur la configuration des modes cache de session.
REPL
, chaque nœud peut stocker 800 sessions en mémoire. Avec le mode cache DIST
désactivé, et la configuration owners
définie par défaut sur 2
, chaque nœud stocke 200 sessions en mémoire.
9.3. Domaine du cookie
9.3.1. Cookie Domain
/
. Cela signifie que seul l'hôte d'origine peut lire le contenu d'un cookie. Le fait de configurer un domaine de cookie particulier rend le contenu du cookie disponible à un plus grand nombre d'hôtes. Pour configurer le domaine de cookie, veuillez vous référer à Section 9.3.2, « Configurer Cookie Domain ».
9.3.2. Configurer Cookie Domain
http://app1.xyz.com
et http://app2.xyz.com
à partager un contexte SSO, même si ces applications fonctionnent sur des serveurs différents dans un cluster ou si l'hôte virtuel avec lequel ils sont associés possède plusieurs alias.
Exemple 9.4. Exemple de configuration de domaine de cookie
<Valve className="org.jboss.web.tomcat.service.sso.ClusteredSingleSignOn" cookieDomain="xyz.com" />
9.4. Implémenter un Singleton HA
La procédure suivante illustre comment déployer un Service qui se trouve dans un decorator de SingletonService et qui est utilisé comme service singleton dans l'ensemble du cluster. Le service active une minuterie programmée, qui n'est lancée qu'à une seule reprise dans le cluster.
Procédure 9.3. Implémenter un Service HA Singleton
Rédiger une application de Service HA Singleton
Voici un exemple simple deService
se trouvant dans le decoratorSingletonService
devant être déployé comme service singleton. On trouvera un exemple complet dans le quickstart decluster-ha-singleton
qui est livré avec Red Hat JBoss Enterprise Application Platform 6. Ce quickstart contient toutes les instructions pour générer et déployer l'application.Créer un service.
Voici un exemple de service :package org.jboss.as.quickstarts.cluster.hasingleton.service.ejb; import java.util.Date; import java.util.concurrent.atomic.AtomicBoolean; import javax.naming.InitialContext; import javax.naming.NamingException; import org.jboss.logging.Logger; import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; /** * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ public class HATimerService implements Service<String> { private static final Logger LOGGER = Logger.getLogger(HATimerService.class); public static final ServiceName SINGLETON_SERVICE_NAME = ServiceName.JBOSS.append("quickstart", "ha", "singleton", "timer"); /** * A flag whether the service is started. */ private final AtomicBoolean started = new AtomicBoolean(false); /** * @return the name of the server node */ public String getValue() throws IllegalStateException, IllegalArgumentException { LOGGER.infof("%s is %s at %s", HATimerService.class.getSimpleName(), (started.get() ? "started" : "not started"), System.getProperty("jboss.node.name")); return ""; } public void start(StartContext arg0) throws StartException { if (!started.compareAndSet(false, true)) { throw new StartException("The service is still started!"); } LOGGER.info("Start HASingleton timer service '" + this.getClass().getName() + "'"); final String node = System.getProperty("jboss.node.name"); try { InitialContext ic = new InitialContext(); ((Scheduler) ic.lookup("global/jboss-cluster-ha-singleton-service/SchedulerBean!org.jboss.as.quickstarts.cluster.hasingleton.service.ejb.Scheduler")).initialize("HASingleton timer @" + node + " " + new Date()); } catch (NamingException e) { throw new StartException("Could not initialize timer", e); } } public void stop(StopContext arg0) { if (!started.compareAndSet(true, false)) { LOGGER.warn("The service '" + this.getClass().getName() + "' is not active!"); } else { LOGGER.info("Stop HASingleton timer service '" + this.getClass().getName() + "'"); try { InitialContext ic = new InitialContext(); ((Scheduler) ic.lookup("global/jboss-cluster-ha-singleton-service/SchedulerBean!org.jboss.as.quickstarts.cluster.hasingleton.service.ejb.Scheduler")).stop(); } catch (NamingException e) { LOGGER.error("Could not stop timer", e); } } } }
Créer un activator qui installe le
Service
en tant que singleton clusterisé.La liste suivante est un exemple d'activateurr de service qui installe leHATimerService
comme service singleton clusterisé :package org.jboss.as.quickstarts.cluster.hasingleton.service.ejb; import org.jboss.as.clustering.singleton.SingletonService; import org.jboss.logging.Logger; import org.jboss.msc.service.DelegatingServiceContainer; import org.jboss.msc.service.ServiceActivator; import org.jboss.msc.service.ServiceActivatorContext; import org.jboss.msc.service.ServiceController; /** * Service activator that installs the HATimerService as a clustered singleton service * during deployment. * * @author Paul Ferraro */ public class HATimerServiceActivator implements ServiceActivator { private final Logger log = Logger.getLogger(this.getClass()); @Override public void activate(ServiceActivatorContext context) { log.info("HATimerService will be installed!"); HATimerService service = new HATimerService(); SingletonService<String> singleton = new SingletonService<String>(service, HATimerService.SINGLETON_SERVICE_NAME); /* * To pass a chain of election policies to the singleton, for example, * to tell JGroups to prefer running the singleton on a node with a * particular name, uncomment the following line: */ // singleton.setElectionPolicy(new PreferredSingletonElectionPolicy(new SimpleSingletonElectionPolicy(), new NamePreference("node2/cluster"))); singleton.build(new DelegatingServiceContainer(context.getServiceTarget(), context.getServiceRegistry())) .setInitialMode(ServiceController.Mode.ACTIVE) .install() ; } }
Note
L'exemple de code ci-dessus utilise une classe,org.jboss.as.clustering.singleton.SingletonService
, qui fait partie de l'API privée de JBoss EAP. Une API publique deviendra disponible dans la version EAP 7 et les classes privées seront obsolètes, mais ces classes seront entretenues et rendues disponible pendant toute la durée du cycle de version EAP 6.x.Créer un fichier ServiceActivator
Créer un fichier nomméorg.jboss.msc.service.ServiceActivator
dans le répertoireresources/META-INF/services/
de l'application. Ajouter une ligne contenant le nom complet de la classe de Service Activator créée dans l'étape précédente.org.jboss.as.quickstarts.cluster.hasingleton.service.ejb.HATimerServiceActivator
Créer un bean singleton qui implémente une minuterie de singleton à utiliser dans tout le cluster.
Ce bean Singleton ne doit pas avoir d'interface distante et ne doit pas référencer son interface locale à partir d'un autre EJB d'application. Cela évite une recherche client ou de la part d'un autre composant et assure un parfait contrôle du Singleton par le SingletonService.Créer une interface de planification.
package org.jboss.as.quickstarts.cluster.hasingleton.service.ejb; /** * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ public interface Scheduler { void initialize(String info); void stop(); }
Créer le bean Singleton qui implémente la minuterie de singleton à utiliser dans tout le cluster.
package org.jboss.as.quickstarts.cluster.hasingleton.service.ejb; import javax.annotation.Resource; import javax.ejb.ScheduleExpression; import javax.ejb.Singleton; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerConfig; import javax.ejb.TimerService; import org.jboss.logging.Logger; /** * A simple example to demonstrate a implementation of a cluster-wide singleton timer. * * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ @Singleton public class SchedulerBean implements Scheduler { private static Logger LOGGER = Logger.getLogger(SchedulerBean.class); @Resource private TimerService timerService; @Timeout public void scheduler(Timer timer) { LOGGER.info("HASingletonTimer: Info=" + timer.getInfo()); } @Override public void initialize(String info) { ScheduleExpression sexpr = new ScheduleExpression(); // set schedule to every 10 seconds for demonstration sexpr.hour("*").minute("*").second("0/10"); // persistent must be false because the timer is started by the HASingleton service timerService.createCalendarTimer(sexpr, new TimerConfig(info, false)); } @Override public void stop() { LOGGER.info("Stop all existing HASingleton timers"); for (Timer timer : timerService.getTimers()) { LOGGER.trace("Stop HASingleton timer: " + timer.getInfo()); timer.cancel(); } } }
Démarrez chaque instance de JBoss EAP 6 avec le clustering activé.
Pour activer le clustering dans les serveurs autonomes, démarrer chaque serveur par le profilHA
, en utilisant un nom de code unique et un offset (décallage) de port pour chaque instance comme suit :- Dans Linux, on utilise la commande suivante pour démarrer les serveurs :
EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml -Djboss.node.name=UNIQUE_NODE_NAME -Djboss.socket.binding.port-offset=PORT_OFFSET
Exemple 9.5. Démarrage de multiples serveurs autonomes sur Linux
$ EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml -Djboss.node.name=node1
$ EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml -Djboss.node.name=node2 -Djboss.socket.binding.port-offset=100
- Dans Microsoft Windows, on utilise la commande suivante pour démarrer les serveurs :
EAP_HOME\bin\standalone.bat --server-config=standalone-ha.xml -Djboss.node.name=UNIQUE_NODE_NAME -Djboss.socket.binding.port-offset=PORT_OFFSET
Exemple 9.6. Démarrage de multiples serveurs autonomes dans Microsoft Windows
C:> EAP_HOME\bin\standalone.bat --server-config=standalone-ha.xml -Djboss.node.name=node1
C:> EAP_HOME\bin\standalone.bat --server-config=standalone-ha.xml -Djboss.node.name=node2 -Djboss.socket.binding.port-offset=100
Note
Si vous ne souhaitez pas utiliser des arguments en ligne de commande, vous pouvez configurer le fichierstandalone-ha.xml
pour que chaque instance de serveur puisse se lier à une interface séparée.Déployer l'application dans les serveurs
Si vous utilisez la commande Maven suivante pour déployer votre application dans un serveur autonome qui exécute sur les ports par défaut.mvn clean install jboss-as:deploy
Pour déployer des serveurs supplémentaires, indiquer le nom du serveur. S'il est sur un hôte différent, passez le nom d'hôte et le numéro de port dans la ligne de commande :mvn clean package jboss-as:deploy -Djboss-as.hostname=localhost -Djboss-as.port=10099
Voir le quickstartcluster-ha-singleton
fourni dans JBoss EAP 6 pour la configuration et les détails de déploiement de Maven.
9.5. Application Apache mod_cluster-manager
9.5.1. L'application mod_cluster-manager
9.5.2. L'application mod_cluster-manager

Figure 9.1. La page web d'administration de mod_cluster
- [1] mod_cluster/1.2.8.Final : indique la version de la bibliothèque de mod_cluster native
- [2] ajp://192.168.122.204:8099: indique le protocole utilisé (un parmi AJP, HTTP, HTTPS), le nom d'hôte ou l'adresse IP d'un noeud de worker et le port
- [3] jboss-eap-6.3-2: indique la JVMRoute du noeud de worker.
- [4] Virtual Host 1: indique le(s) hôte(s) virtuel(s) configuré(s) sur le noeud de worker
- [5] Disable : il s'agit d'une option administrative qui peut être utilisée pour désactiver la création de nouvelles sessions dans un contexte particulier. Cependant, les sessions courantes ne sont pas désactivées et demeurent intactes.
- [6] Stop : il s'agit d'une option administrative qui peut être utilisée pour stoper la redirection de demandes de sessions au contexte. Les sessions restantes seront reprises par défaut par un autre noeud à moins que la propriété
sticky-session-force
soit définie sur "true" - [7] Enable Contexts Disable Contexts Stop Contexts (Activer les contextes Désativer les contextes Stopper les contextes) : opérations qui peuvent être effectuées sur tout le noeud. En sélectionnant une de ces options, vous affectez tous les contextes de noeuds dans tous ses hôtes virtuels.
- [8] Load balancing group (LBGroup): la propriété
load-balancing-group
est définie dans le sous-système mod_cluster dans la configuration EAP pour regrouper tous les noeuds de worker en groupes d'équilibrage de charges personnalisés. Le groupe d'équilibrage de charge (LBGroup) est un champ informel qui donne des informations sur tous les groupes d'équilibrage de charge définis. Si ce champ n'est pas défini, alors tous les noeuds de worker sont regroupés en un seul groupe d'équilibrage de charges par défaut.Note
Il s'agit d'un champ informationnel qui ne peut donc pas être utilisé pour définir la propriétéload-balancing-group
. Cette propriété doit être définie dans le sous-système mod_cluster dans la configuration EAP. - [9] Load (value) : indique la charge sur le noeud de worker. Les « load factors » ou facteurs de charge sont évalués ainsi :
-load > 0
: un facteur de charge de 1 indique une surcharge du noeud de worker, 100 indique qu'il est libre de toute charge.-load = 0
: un facteur de charge de 0 indique que le noeud de worker est en attente, c-a-d qu'aucune demande de session ne sera redirigée vers ce noeud sauf si les autres noeuds de worker ne sont pas disponibles-load = -1
: un facteur de charge de -1 indique qu'il y a une erreur dans l'état du noeud de worker.-load = -2
: un facteur de charge de -2 indique que le noeud de worker est en cours de CPing/CPong et se trouve dans un état de transition
Chapitre 10. CDI
10.1. CDI
10.1.1. CDI
10.1.2. CDI (Contexts and Dependency Injection)
10.1.3. Avantages de CDI
- CDI simplifie et rétrécit votre base code en remplaçant des gros morceaux de code par des annotations.
- CDI est flexible, ce qui vous permet de désactiver ou d'activer des injections et des événements, d'utiliser des autres beans, ou d'injecter des objets non-CDI facilement.
- Il est facile d'utiliser votre ancien code avec CDI. Vous n'avez qu'à y inclure un
beans.xml
dans votre répertoireMETA-INF/
ouWEB-INF/
. Le fichier peut être vide. - CDI simplifie le packaging et les déploiements, et réduit le montant d'XML que vous aurez besoin d'ajouter à vos déploiements.
- CDI propose une gestion du cycle de vie par contexte. Vous pouvez lier des injections aux requêtes, sessions, conversations, ou contextes personnalisés.
- CDI propose une injection de dépendance type-safe, qui est plus sécurisée et facile à débogger qu'une injection basée string.
- CDI découple les intercepteurs des beans.
- CDI fournit une notification d'événements complexe.
10.1.4. Injection de dépendance de Type-safe
10.1.5. Relation entre Weld, Seam 2, Seam 3, et JavaServer Faces
10.2. Utiliser CDI
10.2.1. Premières étapes
10.2.1.1. Activer CDI
Le CDI (Contexts and Dependency Injection) est l'une des technologies de base de la JBoss EAP 6, et est activé par défaut. Si, pour une raison ou une autre, il était désactivé et que vous souhaitiez l'activer, veuillez suivre le procédé suivant :
Procédure 10.1. Activer le CDI dans JBoss EAP 6
Vérifier si les informations du sous-système sont dé-commentées dans le fichier de configuration.
On peut désactiver un sous-système en dé-commentant la section qui convient dans les fichiers de configurationdomain.xml
oustandalone.xml
, ou en supprimant la section qui convient.Pour trouver le sous-système dansEAP_HOME/domain/configuration/domain.xml
ouEAP_HOME/standalone/configuration/standalone.xml
, le chercher dans les strings suivants. S'il existe, il se trouve dans la section <extensions>.<extension module="org.jboss.as.weld"/>
La ligne suivante doit se trouver dans le profil que vous utilisez. Les profils se trouvent dans des éléments de <profile> dans la section <profiles>.<subsystem xmlns="urn:jboss:domain:weld:1.0"/>
Avant de modifier un fichier, arrêter JBoss EAP 6.
JBoss EAP 6 modifie les fichiers de configuration pendant le temps d'exécution, vous devez donc stopper le serveur avant de modifier directement les fichiers de configuration.Modifer le fichier de configuration pour restaurer le sous-système CDI.
Si le sous-système CDI est dé-commenté, supprimer les commentaires.S'il était supprimé totalement, le restaurer en ajoutant cette ligne au fichier dans une nouvelle ligne directement au dessus de la balise </extensions> :<extension module="org.jboss.as.weld"/>
- Vous devez également ajouter la ligne suivante dans le profil concerné qui se trouve dans la section <profiles>.
<subsystem xmlns="urn:jboss:domain:weld:1.0"/>
Démarrer à nouveau JBoss EAP 6.
Démarrer JBoss EAP 6 avec votre configuration mise à jour.
JBoss EAP 6 démarre avec le sous-système CDI activé.
10.2.2. Utiliser CDI pour développer une application
10.2.2.1. Utiliser le CDI pour développer une application
Le CDI (Contexts and Dependency Injection) vous offre une très grande flexibilité pour développer des applications, réutiliser des codes, adapter votre code au déploiement ou à l'exécution et tester des unités. JBoss EAP 6 comprend Weld, l'implémentation de référence de CDI. Ces tâches vous montrent comment utiliser CDI dans vos applications Enterprise.
10.2.2.2. CDI avec le code existant
beans.xml
dans le répertoire META-INF/
ou WEB-INF/
de votre archive. Ce fichier peut rester vide.
Procédure 10.2. Utiliser les anciens beans dans les applications CDI
Groupez vos beans dans une archive.
Groupez vos beans dans une archive JAR ou WAR.Inclure un fichier
beans.xml
dans votre archive.Mettez un fichierbeans.xml
dans votre répertoire d'archive JARMETA-INF/
ou d'archive WARWEB-INF/
. Ce fichier peut rester vide.
Vous pouvez utiliser ces beans avec CDI. Le conteneur peut créer et détruire des instances de vos beans et les associer à un contexte désigné, les injecter dans les autres beans, les utiliser dans des expressions EL, les spécialiser par des annotations de qualificateur et y ajouter des intercepteurs et des décorateurs, sans aucune modification de votre code existant. Dans certains cas, vous devrez peut-être ajouter des annotations.
10.2.2.3. Exclure les beans du processus de balayage
Une des caractéristiques de Weld, l'implémentation de CDI de JBoss EAP 6, est la possibilité d'exclure des classes de balayage de votre archive, d'avoir des événements de cycle de vie conteneur émis, et déployés comme beans. Cela ne fait pas partie de la spécification JSR-299.
Exemple 10.1. Exclure des packages de votre bean.
- Le premier exclut toutes les classes Swing.
- Le second exclut les classes Google Web Toolkit si le Google Web Toolkit n'est pas installé.
- Le troisième exclut les classes qui finissent dans la chaîne
Blether
(en utilisant une expression régulière), si la propriété de système verbosity est définie commelow
. - Le quatrième exclut les classes JSF (Java Server Faces) si les classes Wicket sont présentes et la propriété de système viewlayer n'est pas définie.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:weld="http://jboss.org/schema/weld/beans" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd http://jboss.org/schema/weld/beans http://jboss.org/schema/weld/beans_1_1.xsd"> <weld:scan> <!-- Don't deploy the classes for the swing app! --> <weld:exclude name="com.acme.swing.**" /> <!-- Don't include GWT support if GWT is not installed --> <weld:exclude name="com.acme.gwt.**"> <weld:if-class-available name="!com.google.GWT"/> </weld:exclude> <!-- Exclude classes which end in Blether if the system property verbosity is set to low i.e. java ... -Dverbosity=low --> <weld:exclude pattern="^(.*)Blether$"> <weld:if-system-property name="verbosity" value="low"/> </weld:exclude> <!-- Don't include JSF support if Wicket classes are present, and the viewlayer system property is not set --> <weld:exclude name="com.acme.jsf.**"> <weld:if-class-available name="org.apache.wicket.Wicket"/> <weld:if-system-property name="!viewlayer"/> </weld:exclude> </weld:scan> </beans>
10.2.2.4. Utiliser une injection pour étendre une implémentation
Vous pouvez utiliser une injection pour ajouter ou modifier une caractéristique de votre code existant. Cet exemple vous montre comment ajouter une capacité de traduction à une classe existante. La traduction est une caractéristique hypothétique et la façon dont elle est implémentée dans cet exemple est par pseudo-code, et elle est fournie à titre illustratif uniquement.
buildPhrase
. La méthode buildPhrase
utilise le nom d'une ville comme paramètre et crée une formule telle que "Welcome to Boston". Votre objectif est de créer une version de cette classe Welcome
pouvant traduire cette formule d'accueil dans une autre langue.
Exemple 10.2. Injecter un Bean Translator
dans la classe Welcome
.
Translator
hypothétique dans la classe Welcome
. L'objet Translator
peut être un bean sans état EJB ou un autre type de bean, pouvant traduire des phrases d'une langue à une autre. Ainsi, le Translator
est utilisé pour traduire la formule d'accueil complète, sans avoir à modifier la classe Welcome
d'origine. Le Translator
est injecté avant que la méthode buildPhrase
ne soit implémentée.
public class TranslatingWelcome extends Welcome { @Inject Translator translator; public String buildPhrase(String city) { return translator.translate("Welcome to " + city + "!"); } ... }
10.2.3. Dépendances ambigues ou non satisfaites
10.2.3.1. Dépendances ambigües et non-satisfaites
- Il résout les annotations de qualificateur sur tous les beans qui implémentent le bean d'un point d'injection.
- Il filre les beans désactivés. Les beans désactivés sont des beans @Alternative qui ne sont pas explicitement activés.
10.2.3.2. Qualificateurs
Exemple 10.3. Définit les qualificateurs @Synchronous
et @Asynchronous
@Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Synchronous {}
@Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Asynchronous {}
Exemple 10.4. Utiliser les qualificateurs @Synchronous
et @Asynchronous
@Synchronous public class SynchronousPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
@Asynchronous public class AsynchronousPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
10.2.3.3. Utiliser un qualificateur pour résoudre une injection ambiguë
Cette tâche indique une injection ambiguë et la retire par un qualificateur. Pour en savoir plus sur les injections ambiguës, voir Section 10.2.3.1, « Dépendances ambigües et non-satisfaites ».
Exemple 10.5. Injections ambiguës
Welcome
, une qui traduit, et l'autre non. Dans cette situation, l'injection ci-dessous est ambiguë et a besoin d'être spécifiée pour qu'on puisse utiliser la classe de traduction Welcome
.
public class Greeter { private Welcome welcome; @Inject void init(Welcome welcome) { this.welcome = welcome; } ... }
Procédure 10.3. Résoudre une injection ambiguë avec un qualificateur
Créer une annotation de qualificateur nommée
@Translating
.@Qualifier @Retention(RUNTIME) @Target({TYPE,METHOD,FIELD,PARAMETERS}) public @interface Translating{}
Annoter votre classe
Welcome
par l'annotation@Translating
.@Translating public class TranslatingWelcome extends Welcome { @Inject Translator translator; public String buildPhrase(String city) { return translator.translate("Welcome to " + city + "!"); } ... }
Demander la classe de traduction
Welcome
dans votre injection.Vous devez demander une implémentation explicitement qualifiée, qui ressemble au modèle de la méthode de fabrique. L'ambiguité se résout au point d'injection.public class Greeter { private Welcome welcome; @Inject void init(@Translating Welcome welcome) { this.welcome = welcome; } public void welcomeVisitors() { System.out.println(welcome.buildPhrase("San Francisco")); } }
Translating
Welcome
est utilisé, et il n'y a pas d'ambiguité.
10.2.4. Beans gérés
10.2.4.1. Les beans gérés
bean
.
@Inject
) est un bean. Cela inclut chaque JavaBean et chaque bean de session EJB. La seule exigence pour activer les services mentionnés dans les beans est qu'ils résident dans une archive (un JAR ou un module Java EE comme un WAR ou JAR EJB) qui contienne un fichier spécial marqueur : META-INF/beans.xml
.
10.2.4.2. Types de Classes qui ne sont pas des Beans
@ManagedBean
, mais en CDI cela n'est pas nécessaire. Conformément à la spécification, le conteneur CDI traite n'importe quelle classe qui remplit les conditions suivantes en tant que bean géré :
- Il s'agit d'une classe interne non-statique
- Il ne s'agit pas d'une classe concrète, ou bien elle est annotée par
@Decorator
- Elle n'est pas annotée par une annotation définie par un composant EJB, ni déclarée comme classe bean EJB dans
ejb-jar.xml
. - Elle n'implémente pas l'interface
javax.enterprise.inject.spi.Extension
. - Elle possède soit un constructeur sans paramètre soit un constructeur annoté avec
@Inject
.
10.2.4.3. Utiliser le CDI pour injecter un objet dans un bean
META-INF/beans.xml
ou WEB-INF/beans.xml
, chaque objet de votre déploiement peut être injecté par le CDI.
Injecter un objet dans n'importe quelle partie de bean par l'annotation
@Inject
.Pour obtenir une instance de classe, dans votre bean, annotez ce champ avec@Inject
.Exemple 10.6. Injecter une instance
TextTranslator
dans unTranslateController
public class TranslateController { @Inject TextTranslator textTranslator; ...
Utiliser les méthodes de l'objet injecté
Vous pouvez directement utiliser les méthodes de vos objets injectés. Partez du principe queTextTranslator
possède une méthodetranslate
.Exemple 10.7. Utiliser les méthodes de l'objet injecté
// in TranslateController class public void translate() { translation = textTranslator.translate(inputText); }
Utiliser l'injection dans le contructeur d'un bean
Vous pouvez injecter des objets dans le constructeur d'un bean, ou bien, vous pouvez utiliser une fabrique ou un localisateur de service pour les créer.Exemple 10.8. Utiliser l'injection pour la construction d'un bean
public class TextTranslator { private SentenceParser sentenceParser; private Translator sentenceTranslator; @Inject TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) { this.sentenceParser = sentenceParser; this.sentenceTranslator = sentenceTranslator; } // Methods of the TextTranslator class ... }
Utiliser l'interface
Instance(<T>)
pour obtenir les instances de façon programmatique.L'interfaceInstance
peut renvoyer une instance de TextTranslator si paramétrée par le type de bean.Exemple 10.9. Obtenir une instance par programmation
@Inject Instance<TextTranslator> textTranslatorInstance; ... public void translate() { textTranslatorInstance.get().translate(inputText); }
Lorsque vous injectez un objet dans un bean, toutes les méthodes et les propriétés de l'objet sont disponibles pour votre bean. Si vous injectez dans le constructeur de votre bean, les instances des objets injectés sont créés quand le constructeur de votre bean est appelé, à moins que l'injection ne fasse référence à une instance qui existe déjà. Par exemple, une nouvelle instance ne serait pas créée si vous injectiez un bean basé-session pendant la durée de la session.
10.2.5. Contextes, Scopes et Dépendances
10.2.5.1. Contextes et scopes
@RequestScoped
, @SessionScoped
, et @ConversationScope
.
10.2.5.2. Contextes disponibles
Tableau 10.1. Contextes disponibles
Contexte | Description |
---|---|
@Dependent | Le bean est lié au cycle de vie du bean qui contient la référence. |
@ApplicationScoped | Lié au cycle de vie de l'application. |
@RequestScoped | Lié au cycle de vie de la requête. |
@SessionScoped | Lié au cycle de vie de la session. |
@ConversationScoped | Lié au cycle de vie de la conversation. Le scope de la conversation correspond aux longueurs de la requête et de la session, et est contrôlé par l'application. |
Scopes personnalisés | Si les contextes ne correspondent pas à vos besoins, vous pourrez définir des scopes personnalisés. |
10.2.6. Cycle de vie d'un bean
10.2.6.1. Gestion du cycle de vie d'un bean
Cette tâche vous montre comment sauvegarder un bean pendant la durée de vie d'une requête. Il existe plusieurs autres scopes, et vous pouvez définir vos propres scopes.
@Dependent
. Cela veut dire que le cycle de vie du bean dépend du cycle de vie du bean qui contient la référence. Pour plus d'informations, voir Section 10.2.5.1, « Contextes et scopes ».
Procédure 10.4. Gestion du cycle de vie d'un bean
Annoter le bean par le scope qui correspond au scope désiré.
@RequestScoped @Named("greeter") public class GreeterBean { private Welcome welcome; private String city; // getter & setter not shown @Inject void init(Welcome welcome) { this.welcome = welcome; } public void welcomeVisitors() { System.out.println(welcome.buildPhrase(city)); } }
Quand votre bean est utilisé dans la vue JSF, il contient un état.
<h:form> <h:inputText value="#{greeter.city}"/> <h:commandButton value="Welcome visitors" action="#{greeter.welcomeVisitors}"/> </h:form>
Votre bean est sauvegardé dans le contexte lié au scope que vous spécifiez, et dure aussi longtemps que le scope est applicable.
10.2.6.2. Utilisation d'une méthode Producer
Cette tâche vous montre comment utiliser les méthodes Producer pour créer un certain nombre d'objets qui ne sont pas des beans, pour l'injection.
Exemple 10.10. Utiliser une méthode Producer au lieu d'une méthode Alternative, pour permettre le polymorphisme suite au déploiement.
@Preferred
dans l'exemple donné est une annotation qualifiante. Pour plus d'informations sur les qualificateurs, veuillez vous référer à : Section 10.2.3.2, « Qualificateurs ».
@SessionScoped public class Preferences implements Serializable { private PaymentStrategyType paymentStrategy; ... @Produces @Preferred public PaymentStrategy getPaymentStrategy() { switch (paymentStrategy) { case CREDIT_CARD: return new CreditCardPaymentStrategy(); case CHECK: return new CheckPaymentStrategy(); default: return null; } } }
@Inject @Preferred PaymentStrategy paymentStrategy;
Exemple 10.11. Assigner un scope à une méthode Producer
@Dependent
. Si vous attribuez un scope à un bean, celle-ci est destinée au contexte approprié. La méthode Producer dans cet exemple n'est appelée qu'une fois par session.
@Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy() { ... }
Exemple 10.12. Utiliser une injection à l'intérieur d'une méthode Producer
@Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps, CheckPaymentStrategy cps ) { switch (paymentStrategy) { case CREDIT_CARD: return ccps; case CHEQUE: return cps; default: return null; } }
Note
Les méthodes Producer vous permettent d'injecter des objets non-bean et de changer votre code de façon dynamique.
10.2.7. Beans nommés et beans alternatifs
10.2.7.1. Named Beans
@Named
. Nommer un bean vous permet de l'utiliser directement dans JSF (Java Server Faces).
@Named
prend un paramètre optionnel, qui correspond au nom du bean. Si le paramètre est omis, le nom du bean en minuscules sera utilisé.
10.2.7.2. Utilisation des Named Beans
Utiliser l'annotation
@Named
pour assigner un nom à un bean.@Named("greeter") public class GreeterBean { private Welcome welcome; @Inject void init (Welcome welcome) { this.welcome = welcome; } public void welcomeVisitors() { System.out.println(welcome.buildPhrase("San Francisco")); } }
Le nom du bean en soi est une option. Si vous l'oubliez, le bean sera nommé par rapport à son nom de classe, avec la première lettre non capitalisée. Dans l'exemple ci-dessus, le nom par défaut serait doncgreeterBean
.Utiliser le bean nommé dans une vue JSF
<h:form> <h:commandButton value="Welcome visitors" action="#{greeter.welcomeVisitors}"/> </h:form>
Votre bean nommé correspond à une action dans le contrôle de votre vue JSF, et à un minimum de code.
10.2.7.3. Beans Alternative
Exemple 10.13. Définition d'alternative
@Alternative @Synchronous @Asynchronous public class MockPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
beans.xml
.
10.2.7.4. Remplacer une injection par une alternative
Les beans alternatifs vous permettent de remplacer des beans existants. On peut les concevoir comme un moyen d'ajouter une classe qui remplit le même rôle, mais qui fonctionne différemment. Ils sont désactivés par défaut. Cette tâche vous montre comment indiquer et activer une alternative.
Procédure 10.5. Remplacer une injection
TranslatingWelcome
dans votre projet, mais que vous souhaitez la remplacer par une "fausse" classe TranslatingWelcome. Cela serait le cas pour un déploiement test, où le vrai bean Translator ne peut être utilisé.
Définir l'alternative.
@Alternative @Translating public class MockTranslatingWelcome extends Welcome { public String buildPhrase(string city) { return "Bienvenue à " + city + "!"); } }
Substituer l'alternative.
Pour activer l'implémentation de substitution, ajouter le nom complet de la classe à votre fichierMETA-INF/beans.xml
ouWEB-INF/beans.xml
.<beans> <alternatives> <class>com.acme.MockTranslatingWelcome</class> </alternatives> </beans>
L'implémentation alternative est maintenant utilisée à la place de l'implémentation d'origine.
10.2.8. Stérétypes
10.2.8.1. Stéréotypes
- scope par défaut
- un groupe de liaisons d'intercepteur
- tous les beans avec un stéréotype ont des noms EL de bean par défaut
- tous les beans avec un stéréotype sont des alternatifs
@Named
, tout bean sur lequel elle se trouve a un nom de bean par défaut. Le bean peut remplacer ce nom si l'annotation @Named est directement spécifiée sur le bean. Pour plus d'informations sur les beans nommés, voir Section 10.2.7.1, « Named Beans ».
10.2.8.2. Utilisation des stéréotypes
Sans les stéréotypes, les annotations peuvent devenir encombrées. Cette tâche vous montre comment utiliser les stéréotypes pour réduire l'encombrement et simplifier votre code. Pour plus d'informations sur ce que sont les stéréotypes, voir Section 10.2.8.1, « Stéréotypes ».
Exemple 10.14. Encombrement d'annotation
@Secure @Transactional @RequestScoped @Named public class AccountManager { public boolean transfer(Account a, Account b) { ... } }
Procédure 10.6. Définition et utilisation des stéréotypes
Définir le stéréotype
@Secure @Transactional @RequestScoped @Named @Stereotype @Retention(RUNTIME) @Target(TYPE) public @interface BusinessComponent { ... }
Utilisation d'un stéréotype.
@BusinessComponent public class AccountManager { public boolean transfer(Account a, Account b) { ... } }
Les stéréotypes rationalisent et simplifient votre code.
10.2.9. Méthodes Observer
10.2.9.1. Méthodes Observer
10.2.9.2. Appliquer et observer des événements
Exemple 10.15. Appliquer un événement
public class AccountManager { @Inject Event<Withdrawal> event; public boolean transfer(Account a, Account b) { ... event.fire(new Withdrawal(a)); } }
Exemple 10.16. Appliquer un événement par un qualificateur
public class AccountManager { @Inject @Suspicious Event <Withdrawal> event; public boolean transfer(Account a, Account b) { ... event.fire(new Withdrawal(a)); } }
Exemple 10.17. Observer un événement
@Observes
.
public class AccountObserver { void checkTran(@Observes Withdrawal w) { ... } }
Exemple 10.18. Oberver un événement qualifié
public class AccountObserver { void checkTran(@Observes @Suspicious Withdrawal w) { ... } }
10.2.10. Intercepteurs
10.2.10.1. Les intercepteurs
Points d'interception
- Interception de méthodes commerciales
- Un intercepteur de méthode commeciale s'applique aux invocations de méthodes du bean par les clients du bean.
- Interception de lifecycle callback
- Un intercepteur de lifecycle callback s'applique aux invocations de lifecycle callback par le conteneur.
- Interception de méthode de timeout
- Un intercepteur de méthode de timeout s'applique aux invocations de métodes d'EJB timeout par le conteneur.
10.2.10.2. Utiliser les intercepteurs avec le CDI
Exemple 10.19. Intercepteurs sans le CDI
- Le bean doit indiquer l'implémentation de l'intercepteur directement.
- Chaque bean de l'application doit indiquer l'ensemble des intercepteurs dans l'ordre qui convient. Cela fait que l'ajout ou le retrait d'intercepteurs sur la base d'une application prend beaucoup de temps et comporte un risque d'erreur non négligeable.
@Interceptors({ SecurityInterceptor.class, TransactionInterceptor.class, LoggingInterceptor.class }) @Stateful public class BusinessComponent { ... }
Procédure 10.7. Utiliser les intercepteurs avec le CDI
Définir le type de liaison d'intercepteur.
@InterceptorBinding @Retention(RUNTIME) @Target({TYPE, METHOD}) public @interface Secure {}
Marquer l'implémentation de l'intercepteur.
@Secure @Interceptor public class SecurityInterceptor { @AroundInvoke public Object aroundInvoke(InvocationContext ctx) throws Exception { // enforce security ... return ctx.proceed(); } }
Utiliser l'intercepteur dans votre code commercial.
@Secure public class AccountManager { public boolean transfer(Account a, Account b) { ... } }
Activer l'intercepteur dans votre déploiement, en l'ajoutant à votre fichier
META-INF/beans.xml
ouWEB-INF/beans.xml
.<beans> <interceptors> <class>com.acme.SecurityInterceptor</class> <class>com.acme.TransactionInterceptor</class> </interceptors> </beans>
Les intercepteurs sont appliqués dans l'ordre indiqué.
Le CDI simplifie votre code d'intercepteur et simplifie l'application de votre code commercial.
10.2.11. Les décorateurs
@Decorator
.
Exemple 10.20. Exemple de décorateur
@Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Any Account account; @PersistenceContext EntityManager em; public void withdraw(BigDecimal amount) { ... } public void deposit(BigDecimal amount); ... } }
10.2.12. Extensions portables
- intégration par les moteurs de Business Process Management
- intégration aux frameworks de tierce partie comme Spring, Seam, GWT ou Wicket
- nouvelle technologie basée sur le modèle de programmation CDI
- En fournissant ainsi ses propres beans, intercepteurs et décorateurs au conteneur
- En injectant des dépendances dans ses propres objets en utilisant le service d'injections de dépendances
- En fournissant une implémentation de contexte pour un scope personnalisé
- En augmentant ou en remplaçant les métadonnées basées annotation par les métadonnées d'autres sources
10.2.13. Proxies Beans
10.2.13.1. Proxys Bean
Problèmes d'injection de dépendance, qui sont résolus en utilisant les proxys.
- Performance - les proxys sont bien plus rapides que l'injection de dépendance, donc vous pouvez les utiliser dans des beans qui requièrent une haute performance.
- Thread safety - les proxys envoient des requêtes vers l'instance de bean qui convient, même quand plusieurs threads accèdent à un bean en même temps.
Classes qui ne peuvent pas être mises en proxy
- Types Primitives ou Tableaux
- Classes
final
ou qui possèdent une méthodefinal
- Classes qui ont un constructeur non-privé par défaut
10.2.13.2. Utiliser un Proxy ou une Injection
Un proxy est utilisé pour l'injection quand les cycles de vie des beans sont différents les uns des autres. Le proxy est une sous-classe du bean qui est créée au moment de l'exécution et qui remplace toutes les méthodes non privées de la classe de bean. Le serveur proxy transmet l'invocation sur l'instance réelle du bean.
PaymentProcessor
n'est pas injectée directement dans Shop
. À la place, un proxy est injecté, et quand la méthode processPayment()
est appelée, le proxy cherche l'instance de bean courante PaymentProcessor
et appelle la méthode processPayment()
dessus.
Exemple 10.21. Injection de proxy
@ConversationScoped class PaymentProcessor { public void processPayment(int amount) { System.out.println("I'm taking $" + amount); } } @ApplicationScoped public class Shop { @Inject PaymentProcessor paymentProcessor; public void buyStuff() { paymentProcessor.processPayment(100); } }
Chapitre 11. Java Transaction API (JTA)
11.1. Aperçu
11.1.1. Java Transactions API (JTA)
Ces topics vous donnent des explications de base sur l'API Java Transactions (JTA).
11.2. Concepts de transactions
11.2.1. Transactions
11.2.2. Les propriétés ACID de transactions
Atomicity
, Consistency
, Isolation
, et Durability
. Cette terminologie est normalement utilisée dans le contexte de bases de données ou d'opérations transactionnelles.
Définitions ACID
- Atomicité
- Pour qu'une transaction soit atomique, tous les membres de la transaction doivent prendre la même décision. Ils doivent soit tous valider, soit tous se retirer. Si l'atomicité est cassée, ce qui en résultera s'appelle un heuristic outcome..
- Homogénéité
- Homogénéité signifie que les données écrites dans la base de données doivent être valides, en terme de schéma de base de données. La base de donnée et les autres sources de données doivent toujours être dans un état consistant. Par exemple, un état inconsistant pourrait correspondre à un champ dans lequel la moitié des données sont écrites avant qu'une opération n'échoue. Dans le cas d'un état consistant, toutes les données sont écrites, et l'écriture est retirée si incomplète.
- Isolation
- Isolation signifie que les données ajoutées à l'opération doivent être verrouillées avant toute modification, pour ne pas que les processus modifient les données au delà de la portée de la transaction en question.
- Durabilité
- Durabilité signifie qu'en cas d'échec externe, après que les membres d'une transaction aient été instruits de valider, tous les membres seront disponibles pour continuer la validation de la transaction quand l'échec sera résolu. Cette défaillance est sans doute liée au matériel, logiciels, réseau, ou tout autre système impliqué.
11.2.3. Coordinateur de transactions ou Gestionnaire de transactions
11.2.4. Participants à une transaction
11.2.5. JTA (Java Transactions API)
11.2.6. JTS (Java Transaction Service)
Note
11.2.7. Sources de données XA et transactions XA
11.2.8. Recouvrement XA
11.2.9. Le protocole de validation en 2-Phases
Au cours de la première phase, les participants à la transaction indiquent au coordinateur de transaction s'ils sont en mesure de valider la transaction ou bien, s'ils doivent la retirer.
Dans la deuxième phase, le coordinateur de transactions prend la décision de savoir si l'opération globale doit être validée ou bien, retirée. Si l'un des participants ne peut pas valider, la transaction sera retirée. Sinon, l'opération peut être validée. Le coordinateur dirige les opérations et en notifie le coordinateur quand les décisions sont prises. À ce moment-là, la transaction est terminée.
11.2.10. Les délais d'attente des transactions
11.2.11. Les transactions distribuées
11.2.12. API de portabilité ORB
Classes API de la portabilité ORB
com.arjuna.orbportability.orb
com.arjuna.orbportability.oa
11.2.13. Transactions imbriquées
Les avantages des transactions imbriquées
- Isolation des erreurs
- Si une sous-transaction s'annule, par exemple parce qu'un objet utilisé échoue, la transaction englobante ne nécessite pas d'être annulée.
- Modularité
- Si une transaction est déjà associée à un appel quand une nouvelle transaction commence, la nouvelle transaction sera imbriquée à l'intérieur. Dès lors, si vous savez qu'un objet requiert des transactions, vous pouvez les créer dans l'objet. Si les méthodes de l'objet sont invoquées sans une transaction client, alors les transactions de l'objet sont de niveau supérieur. Sinon, elles sont imbriquées dans l'étendue des transactions du client. De la même manière, un client n'a pas besoin de savoir si un objet est transactionnel. Il peut commencer sa propre transaction.
11.3. Optimisations des transactions
11.3.1. Optimisations de transactions
Le sous-système de transactions de JBoss EAP 6 inclut plusieurs optimisations dont vous pouvez tirer avantage dans vos applications.
11.3.2. Optimisation LRCO pour une validation en 1 phase (1 PC)
11.3.2.1. Commit Markable Resource (CRM)
La configuration de l'accès à un gestionnaire de ressources via l'interface CRM de validation de ressources marquables (Commit Markable Resource) garantit que le gestionnaire de ressources 1PC puisse être inscrit dans une transaction 2PC. C'est une implémentation de l'algorithme LRCO, qui rend les ressources non-XA entièrement récupérables.
- Préparer 2PC
- Valider LRCO
- Write tx log
- Commit 2PC
Une transaction peut ne contenir qu'une ressource CMR.
Vous devez avoir un tableau créé pour lequel le SQL suivant fonctionne :
SELECT xid,actionuid FROM _tableName_ WHERE transactionManagerID IN (String[]) DELETE FROM _tableName_ WHERE xid IN (byte[[]]) INSERT INTO _tableName_ (xid, transactionManagerID, actionuid) VALUES (byte[],String,byte[])
Exemple 11.1. Voici quelques exemples de requêtes SQL
CREATE TABLE xids (xid varbinary(144), transactionManagerID varchar(64), actionuid varbinary(28))
CREATE TABLE xids (xid RAW(144), transactionManagerID varchar(64), actionuid RAW(28)) CREATE UNIQUE INDEX index_xid ON xids (xid)
CREATE TABLE xids (xid VARCHAR(255), transactionManagerID varchar(64), actionuid VARCHAR(255)) CREATE UNIQUE INDEX index_xid ON xids (xid)
CREATE TABLE xids (xid varbinary(144), transactionManagerID varchar(64), actionuid varbinary(28)) CREATE UNIQUE INDEX index_xid ON xids (xid)
CREATE TABLE xids (xid bytea, transactionManagerID varchar(64), actionuid bytea) CREATE UNIQUE INDEX index_xid ON xids (xid)
Par défaut, la fonctionnalité CMR est désactivée pour les sources de données. Pour l'activer, vous devez créer ou modifier la configuration de source de données et vous assurer que l'attribut connectable est défini sur true. Voici un exemple d'entrée de configuration de la section sources de données d'un fichier de configuration xml serveur :
<datasource enabled="true" jndi-name="java:jboss/datasources/ConnectableDS" pool-name="ConnectableDS" jta="true" use-java-context="true" spy="false" use-ccm="true" connectable="true"/>
Note
/subsystem=datasources/data-source=ConnectableDS:add(enabled="true", jndi-name="java:jboss/datasources/ConnectableDS", jta="true", use-java-context="true", spy="false", use-ccm="true", connectable="true", connection-url="validConnectionURL", driver-name="h2")
Si vous ne devez mettre à jour qu'une seule ressource existante pour utiliser la nouvelle fonctionnalité CMR, il vous suffira de modifier l'attribut connectable :
/subsystem=datasources/data-source=ConnectableDS:write-attribute(name=connectable,value=true)
Le sous-système de transactions identifie les sources de données qui peuvent utiliser la fonctionnalité CMR par l'intermédiaire d'une entrée dans la section de config du sous-système de transaction comme dans l'exemple ci-dessous :
<subsystem xmlns="urn:jboss:domain:transactions:3.0"> ... <commit-markable-resources> <commit-markable-resource jndi-name="java:jboss/datasources/ConnectableDS"> <xid-location name="xids" batch-size="100" immediate-cleanup="false"/> </commit-markable-resource> ... </commit-markable-resources> </subsystem>
Note