Configurer une WebApp avec JNDI

Une WebApp a quasiment toujours besoin de paramètres de configuration ne serait-ce que pour se connecter à une base de données.
Il existe plusieurs moyens de gérer ces paramètres de configuration tel que les profils Maven voire, si vous êtes resté au XXème siècle, la modification de fichier à la main. Cela demande cependant de livrer une version différente pour chaque environnement ce qui est source d’erreur et fait toujours râler les gens de la production.

Une autre solution existe, il s’agit de JNDI. JNDI va permettre de déclarer dans la configuration du serveur d’application les paramètres de configuration de votre WebApp et donc ainsi de déporter la configuration spécifique à l’environnement. Le principe de base se rapproche des variables d’environnement système à la différence que le serveur d’application va pouvoir directement référencer des objets comme des pools de connexions aux bases de données.
Cette solution a plusieurs avantages. D’une part les développeurs peuvent configurer leurs serveurs en local en gardant un code commun (au revoir les commit qui écrasent la config d’un autre développeur). D’autre part la production va pouvoir livrer le même package en PréProd et en Prod tout en gardant de leur côté les informations sensibles (mots de passe…) et ce, sans avoir à modifier le package à chaque livraison.

Voyons comment mettre en œuvre cette solution à travers la configuration d’une base de données et d’une simple chaîne de caractères.

WebApp

Les modifications dans la WebApp sont assez minimes. L’exemple ci-dessous utilise Spring MVC ce qui facilite encore d’avantage la récupération des objets JNDI.

Il faut tout d’abord définir dans le fichier web.xml les variables JNDI auxquelles vous allez vouloir accéder :

	<!-- JDBC -->
	<resource-ref>
		<res-ref-name>jdbc/jndiDS</res-ref-name>
		<res-type>javax.sql.DataSource</res-type>
		<res-auth>Container</res-auth>
	</resource-ref>

	<!-- Properties -->
	<resource-env-ref>
		<resource-env-ref-name>envName</resource-env-ref-name>
		<resource-env-ref-type>java.lang.String</resource-env-ref-type>
	</resource-env-ref>

La première ressource JNDI est une datasource qui va nous fournir directement l’objet pour se connecter à la base de données. C’est donc le serveur d’application lui même qui va gérer le pool de connexion à la base.
La deuxième ressource est une simple String qui nous donne le nom de l’environnement du serveur d’application.

Voyons maintenant comment injecter les valeurs de ces variables JNDI à l’aide de Spring MVC. Celui-ci dispose d’une balise jee:jndi-lookup pour ce faire :

    <!-- Database -->
    <jee:jndi-lookup jndi-name="jdbc/jndiDS" id="dataSource"/>

    <!-- Creating controllers -->
    <bean id="indexController" class="info.thomazo.alex.web.controllers.IndexController">
    	<property name="dataSource" ref="dataSource"/>
    	<property name="envName"><jee:jndi-lookup jndi-name="java:comp/env/envName"/></property>
    </bean>

Petite subtilité concernant le nom de la ressource String, le nom JNDI doit être précédé de java:comp/env/.

C’est tout, Spring s’occupe de faire le reste pour nous 🙂

Tomcat

Voyons maintenant les modifications à apporter à Tomcat.

La définition des ressources JNDI peut s’effectuer soit pour être commun à toutes les WebApp (un pool pour toutes les applications par exemple), soit pour être instanciée pour chaque WebApp (un pool instancié pour chaque application), soit être spécifique à une seule application.
N’hébergeant par habitude qu’une seule application par instance de Tomcat, j’ai opté pour la deuxième solution, soit une définition commune à tout le serveur mais tout de même instanciée pour chaque application.

La modification s’effectue donc dans le fichier conf/context.xml du répertoire d’installation de Tomcat entre les balises <Context> :

	<Resource
		auth="Container"
		driverClassName="com.mysql.jdbc.Driver"
		factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
		name="jdbc/jndiDS"
		username="dbuser"
		password="dbpass"
		type="javax.sql.DataSource"
		url="jdbc:mysql://dbhost:3306/dbname"
		testOnBorrow="true"
		validationQuery="SELECT 1"
	/>

	<Environment
		name="envName"
		value="dev"
		type="java.lang.String"
	/>

La configuration de la datasource se fait à l’aide de la balise Resource tandis que celle de la String s’effectue avec Environment. Voir en fin d’article pour les liens vers la configuration de la datasource.

Ne pas oublier non plus d’ajouter le jar correspondant à votre base de données dans le répertoire lib/ de Tomcat, dans notre exemple mysql-connector-java-x.y-bin.jar.

Et voilà, rien de bien compliqué non plus ici 🙂

Bien sûr, tous les serveurs d’application permettent de définir des variables JNDI, je vous laisse fouiller pour vous adapter à celui qui vous intéresse.

Log4J

Et si je veux aussi déporter mon log4j.xml à l’extérieur de mon war ?
Pas de problème, dans le projet exemple, j’ai ajouté la classe Log4JInitListener qui se lance donc au démarrage de la WebApp. Cette classe définie dans le fichier web.xml va chercher la ressource JNDI log4jConf qui défini le chemin vers un fichier log4j.xml.

Si la ressource JNDI n’existe pas, rien n’est chargé et le log4j.xml fourni dans le war continu d’être utilisé. Attention tout de même à ce que votre fichier XML externe ne comporte pas d’erreur. En effet, Log4J ne permet pas de détecter les erreurs de parsing d’un fichier donc s’il y a un problème lors de celui-ci, aucune configuration ne sera appliquée.

Conclusion

Vous avez maintenant les premières pistes pour utiliser JNDI. N’hésitez pas, malgré la configuration à faire à la première installation, cela simplifie toutes les autres livraisons 🙂

Voici quelques liens pour finir :

Laisser un commentaire


NOTE - Vous pouvez utiliser les éléments et attributs HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>