<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog de Baptiste Wicht &#187; Conception</title>
	<atom:link href="https://blog.developpez.com/wichtounet/pcategory/programmation/conception/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/wichtounet</link>
	<description></description>
	<lastBuildDate>Fri, 25 Nov 2011 10:34:42 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>OSGi et dépendances cycliques</title>
		<link>https://blog.developpez.com/wichtounet/p8723/jtheque/osgi_et_dependances_cycliques</link>
		<comments>https://blog.developpez.com/wichtounet/p8723/jtheque/osgi_et_dependances_cycliques#comments</comments>
		<pubDate>Sat, 13 Mar 2010 19:07:19 +0000</pubDate>
		<dc:creator><![CDATA[Baptiste Wicht]]></dc:creator>
				<category><![CDATA[Conception]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JTheque]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Bonsoir, je suis en train de travailler sur la &#171;&#160;bundlisation&#160;&#187; de JTheque Core. Comme le core proposait un certain nombre de services, j&#8217;ai commencé par découper le gros jar qu&#8217;était le core en une série de bundles offrant tous un service bien précis. Je me suis vite rendu compte que le découplage de mes différents services était à peu près nul. J&#8217;avais un nombre énorme de dépendances pour chaque bundle et pire encore, j&#8217;avais un [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Bonsoir, </p>
<p>je suis en train de travailler sur la &laquo;&nbsp;bundlisation&nbsp;&raquo; de JTheque Core. Comme le core proposait un certain nombre de services, j&rsquo;ai commencé par découper le gros jar qu&rsquo;était le core en une série de bundles offrant tous un service bien précis. </p>
<p>Je me suis vite rendu compte que le découplage de mes différents services était à peu près nul. J&rsquo;avais un nombre énorme de dépendances pour chaque bundle et pire encore, j&rsquo;avais un grand nombre de dépendances cycliques, soit directs soit indirects. </p>
<p>Pour information, une dépendance cyclique directe est une situation dans laquelle un bundle X dépend d&rsquo;un bundle Y qui dépend lui-même de X. Une dépendance cycle indirecte est la situation dans laquelle X dépend Y, Y dépend de Z et Z dépend de X. Je parle ici de bundles, mais cela peut concerner des projets, des classes ou des packages. </p>
<p>A noter que les différentes techniques que je vais présenter s&rsquo;appliquent également pour des dépendances entre composants non-OSGi, les principes sont tout à fait les mêmes. </p>
<p><span id="more-14"></span></p>
<p>Dans le cas de packages à l&rsquo;intérieur d&rsquo;une même application, même s&rsquo;il faut éviter cela, il est possible de vivre. Néanmoins, dans le cas de bundle ou de projets, il n&rsquo;est en général même pas possible de builder l&rsquo;application. Dans mon cas, les bundles sont des modules Maven. Il est donc impossible de lancer le build d&rsquo;un bundle dans un cycle puisqu&rsquo;il faut builder le premier bundle avant le second et le second avant le premier, ce qui n&rsquo;est pas évidemment pas possible. </p>
<p>En plus d&rsquo;être très mauvais dans un système de build, les dépendances cycliques entre componsants sont aussi un énorme problème de conception. En effet, on ne peut plus travailler sur le bundle A sans travailler sur le bundle B et vice-versa. En plus de cela, les deux composants sont très difficiles à faire évoluer de manière saine. </p>
<p>Les dépendances cycliques au niveau des classes à l&rsquo;intérieur d&rsquo;un composant ne posent pas vraiment de problèmes. On est toujours dans le même composant, les classes peuvent dont être liées de manière cyclique, même s&rsquo;il faudrait tout de même éviter cela dès que c&rsquo;est possible (ça ne l&rsquo;est pas toujours). </p>
<p>Pour en revenir à JTheque, j&rsquo;ai donc du résoudre ce problème de dépendances cycliques avant de pouvoir avancer plus loin. Il existe beaucoup de techniques permettant de faire cela. Voici les différentes pistes que j&rsquo;ai explorées pour résoudre ces dépendances. A noter que ces techiques ne permettent pas seulement de règler le problème des dépendances cycliques mais permet aussi d&rsquo;améliorer l&rsquo;architecture de son application. </p>
<p>1. <strong>Déplacer les classes au bon endroit</strong> : Dans certains cas, j&rsquo;avais des classes dans un bundle alors qu&rsquo;elles n&rsquo;avait rien à y faire. Dans ce cas-là, il peut suffir de les dépacer dans un autre bundle. A noter que ce cas est le plus simple à résoudre et que ce n&rsquo;est malheureusement pas le plsu courant. En plus de cela, dans le cas ou la/les classes à déplacer sont dépendantes d&rsquo;autres bundles, il est possible que cela crée de nouvelles dépendances cycliques. Un exemple est une classe de gestion de modules qui était contenues dans le bundle d&rsquo;interfaces graphiques. </p>
<p>2. <strong>Déplacer les fonctionnalités</strong> : J&rsquo;ai également trouvé beaucoup de fonctionnalités, typiquement des fonctions, à l&rsquo;intérieur d&rsquo;un bundle qui n&rsquo;étaient pas au bon endroit. Par exemple le bundle &laquo;&nbsp;modules&nbsp;&raquo; permettait de faire des mises à jour alors qu&rsquo;un bundle &laquo;&nbsp;update&nbsp;&raquo; existait. Il m&rsquo;a suffi de déplacer cette fonctionnalité de mise à jour vers le bundle update pour résoudre ma dépendance. </p>
<p>3. <strong>Fonctionnalités mal découpées</strong> : Il arrive souvent qu&rsquo;une fonctionnalité, généralement une méthode ou une classe, fasse trop de choses et entraîne des dépendances qui ne sont pas bienvenues ici. Souvent bien redécouper les fonctionnalités et donc le rôle de chaque classe/méthode peut suffir à régler le problème. A noter que ceci ne concerne pas uniquement les concepts de dépendances, mais est un principe de base de la conception orientée objet. Dans le cas de JTheque, j&rsquo;avais pas par exemple, une permettant permettant de choisir une collection qui retournait true si on pouvait ouvrir la collection avec le couple login/password entré sinon false. Mais en plus de cela, elle affichait une erreur dans la vue de choix de collection s&rsquo;il y avait un problème alors que ce n&rsquo;était pas du son rôle. J&rsquo;ai mis à jour cette méthode pour qu&rsquo;elle ne fasse que tester si on pouvait ouvrir la collection ou non et j&rsquo;ai implémenté l&rsquo;affichage de l&rsquo;erreur au niveau de l&rsquo;action Swing. </p>
<p>4. <strong>Découper les fonctionnalités du bundle</strong> : Il peut arriver que le bundle fasse trop de choses ou ait plusieurs aspects bien distincts. Dans ce cas, il faut tout de suite séparer le bundle en plusieurs autres pour que chacun ait une responsabilité claire. Souvent cela va aider à résoudre une dépendance cyclique, comme moins de bundles auront des dépendances vers chacun des nouveaux bundles et que chacun des nouveaux bundles devrait avoir moins de dépendances vers d&rsquo;autres bundles. Mais cela peut également introduire de nouveaux cycles car on peut mal séparer les composants et se retrouver avec 2 composants cycliquement dépendant, on n&rsquo;aura alors fait que déplacer le problème. Dans JTheque, j&rsquo;ai découpé le modules vues en 2 deux bundles : vues et ui. Le module vues contient l&rsquo;implémentation des vues de JTheque alors que le module ui contient des classes utilitaires pour la création de vues ainsi que des composants Swing génériques qui peuvent être utilisés ailleurs. </p>
<p>5. <strong>Introduire un système de CallBack</strong> : Un système de CallBack est un simple système de listeners qui peut permettre de résoudre des dépendances. Au lieu qu&rsquo;un bundle avertisse directement un autre bundle, il suffit que le second s&rsquo;enregistre sur le premier comme listener. Ainsi le premier n&rsquo;a plus besoin de connaître le second. On voit tout de suite que les listeners sont donc plus puissants qu&rsquo;on ne pourrait le croire au premier abord. Dans le cas de JTheque, j&rsquo;ai implémenté cela pour le choix des collections. En effet, de base, le gestionnaire de collections appelait directement la vue pour dire que la collection avait été choisie. En passant à un listener, cela est beaucoup plus souple et le gestionnaire de collections avertit automatiquement tous les écouteurs. En plus de cela, si j&rsquo;ai besoin plus tard d&rsquo;ajouter un second écouteur, je n&rsquo;ai rien à changer du côté du bundle collections. </p>
<p>6. <strong>Séparer la spécification de l&rsquo;implémentation</strong> : Comme il n&rsquo;est pas toujours possible de supprimer les dépendances cycliques directement, on peut donc les contourner en séparant la partie de spécification de la partie d&rsquo;implémentation. Cette technique n&rsquo;est clairement pas la meilleur mais peut parfois être utile quand il est vraiment difficile de résoudre le cycle. On sépare donc dans un bundle toute la partie spécification qui est appelée de l&rsquo;extérieur et la partie d&rsquo;implémentation qui peut alors avoir des dépendances avec l&rsquo;extérieur. A noter que ce n&rsquo;est clairement pas souvent faisable en l&rsquo;état car il n&rsquo;est pas toujours possible de complètement séparer l&rsquo;implémentation de la spécification sans cycles. Je n&rsquo;ai pas utilisé cette technique dans JTheque, mais j&rsquo;y ai pensé. </p>
<p>7. <strong>Regrouper 2 bundles en un seul</strong> : Dans certains cas, on se rend compte que deux modules sont si intrinsèquement liés qu&rsquo;ils ne forment en fait qu&rsquo;un seul modules. Dans ce cas, la meilleure solution est de les regrouper en un seul bundle. </p>
<p>Voilà, j&rsquo;ai maintenant passé en revue les différentes techniques que j&rsquo;ai utilisées pour résoudre les dépendances cycliques dans les bundles de JTheque Core. Il en existe très certainement de nombreuses autres, mais personnellement, elles m&rsquo;ont suffit. </p>
<p>J&rsquo;espère que cela pourra être utile aux personnes cherchant à résoudre des problèmes de dépendances cycliques. </p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Concevoir une application modulaire &#8211; Bases</title>
		<link>https://blog.developpez.com/wichtounet/p6448/perso/concevoir_une_application_modulaire_base</link>
		<comments>https://blog.developpez.com/wichtounet/p6448/perso/concevoir_une_application_modulaire_base#comments</comments>
		<pubDate>Thu, 25 Sep 2008 16:01:00 +0000</pubDate>
		<dc:creator><![CDATA[Baptiste Wicht]]></dc:creator>
				<category><![CDATA[Conception]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JTheque]]></category>
		<category><![CDATA[Mes projets]]></category>
		<category><![CDATA[Perso]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Bonjour, Je suis actuellement en train de développer une application modulaire. Au vu des problèmes que j&#8217;ai rencontré pour développer la partie modules et le peu d&#8217;informations que j&#8217;ai pu trouver sur le net, j&#8217;ai pensé que faire une série de billets sur le sujet ne pourrait qu&#8217;être profitable à tout le monde. Dans ce billet, je vais commencer par parler des bases de la conception d&#8217;une application modulaire, c&#8217;est-à-dire pour commencer, ce qu&#8217;est une [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Bonjour, </p>
<p>Je suis actuellement en train de développer une <strong>application modulaire</strong>. Au vu des problèmes que j&rsquo;ai rencontré pour développer la partie modules et le peu d&rsquo;informations que j&rsquo;ai pu trouver sur le net, j&rsquo;ai pensé que faire une série de billets sur le sujet ne pourrait qu&rsquo;être profitable à tout le monde. </p>
<p>Dans ce billet, je vais commencer par parler des bases de la conception d&rsquo;une application modulaire, c&rsquo;est-à-dire pour commencer, ce qu&rsquo;est une application modulaire, ce qu&rsquo;est un module et bien entendu ce que ça apporte. Dans les prochains billets, je vais essayer de décrire les différentes problématiques inhérentes au sujet et leurs résolutions. Si ces billets nécessitent du code, ces exemples de code seront en Java, car c&rsquo;est le langage que j&rsquo;ai choisi pour développer mon application, mais les concepts peuvent s&rsquo;appliquer à tous les langages. </p>
<p>Bien entendu, je ne me considère pas comme un pro dans les applications modulaires et les différentes informations que je vais donner au fil des billets n&rsquo;est que ma façon de voir, il y en a certainement d&rsquo;autres et des meilleures, donc si vous n&rsquo;êtes pas d&rsquo;accord avec moi ou si vous pensez qu&rsquo;on peut faire mieux, n&rsquo;hésitez pas à réagir en commentant ces billets </p>
<p><span id="more-112"></span></p>
<p>Pour commencer, qu&rsquo;est-ce qu&rsquo;une application modulaire ? Une application modulaire est constituée de 2 parties bien distinctes : </p>
<ul>
<li>Le <strong>coeur </strong>: Comme son nom l&rsquo;indique, il s&rsquo;agit de la partie centrale de l&rsquo;application. Cette partie doit être complètement indépendante des modules. </li>
<li>Les <strong>modules </strong>: Il s&rsquo;agit cette fois des parties qu&rsquo;on va ajouter dynamiquement à l&rsquo;application pour lui rajouter des fonctionnalités. On leur donne d&rsquo;autres noms : briques, plugins, addons, &#8230;, mais le concept est toujours le même. </li>
</ul>
<p>Il y a à mon avis 2 sortes d&rsquo;applications modulaires. Le premier type est une application somme toute normale qui propose une série de fonctionnalités et qui propose en plus de rajouter des fonctionnalités par le biais de modules. Le second type est une application qui propose un coeur complètement dénué de fonctionnalités. Toutes les fonctionnalités sont proposées par les modules, c&rsquo;est donc une application dans laquelle &laquo;&nbsp;tout est module&nbsp;&raquo;. </p>
<p>La différence principale est que la première peut être utilisée tout à fait normalement sans aucun module, alors que la deuxième ne propose pas (ou presque pas) de fonctionnalités sans module. </p>
<p>Au contraire d&rsquo;une application normale, il faut donc prévoir des points d&rsquo;extensions que les modules pourront utiliser pour ajouter des fonctionnalités à l&rsquo;application ou pour modifier l&rsquo;existant. </p>
<p>C&rsquo;est sur ce deuxième type d&rsquo;application modulaire que je suis parti pour réaliser mon logiciel. Cela permet d&rsquo;avoir un socle solide qu&rsquo;on peut éventuellement réutiliser pour d&rsquo;autres applications sous réserve de quelques modifications. </p>
<p>Comme application modulaire connue, on peut citer <a href="http://www.eclipse.org/">Eclipse</a> qui est entièrement modulaire et qui est du deuxième type. </p>
<p>Maintenant, la grande question est : C&rsquo;est bien beau tout ça, mais ça sert à quoi ? Tout d&rsquo;abord, du point de vue du développeur, cela permet de séparer clairement les différentes parties de l&rsquo;application. On a donc des modules distincts plus faciles à maintenir qu&rsquo;une grosse application. Cela permet également d&rsquo;être très souple pour rajouter des fonctionnalités à l&rsquo;application, en effet, pour cela, il suffit de créer un nouveau module, d&rsquo;y coder la fonctionnalité et de rajouter ce module dans l&rsquo;application. Du point de vue de l&rsquo;utilisateur, cela ajoute de la souplesse au programme. En effet, l&rsquo;utilisateur va pouvoir choisir quels modules il veut lancer, rajouter de nouveaux modules, voire même en créer s&rsquo;il en est capable. Il pourra donc personnaliser son application. </p>
<p>Bien entendu, cela ne se fait pas tout seul et ce n&rsquo;est pas des plus simples à concevoir et à implémenter. En effet, cela pose beaucoup de problématiques qu&rsquo;il faut régler et cela implique beaucoup de questions qu&rsquo;il faut se poser. </p>
<p>C&rsquo;est ce que nous verrons dans les prochains articles. </p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Concevoir une application modulaire &#8211; Modules</title>
		<link>https://blog.developpez.com/wichtounet/p6473/perso/concevoir_une_application_modulaire_modu</link>
		<comments>https://blog.developpez.com/wichtounet/p6473/perso/concevoir_une_application_modulaire_modu#comments</comments>
		<pubDate>Sun, 28 Sep 2008 14:33:09 +0000</pubDate>
		<dc:creator><![CDATA[Baptiste Wicht]]></dc:creator>
				<category><![CDATA[Conception]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JTheque]]></category>
		<category><![CDATA[Mes projets]]></category>
		<category><![CDATA[Perso]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Après avoir décrit dans le premier billet en quoi consistait une application modulaire et ce qu&#8217;était un module, nous allons maintenant nous pencher plus spécialement sur les modules. Nous avons dit qu&#8217;un module permettait de rajouter des fonctionnalités à l&#8217;application principale. Mais avant de se lancer dans le moindre code, il va falloir définir exactement ce que seront nos modules, ce qu&#8217;ils pourront faire, s&#8217;il y aura plusieurs types de modules, &#8230; C&#8217;est ce que [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Après avoir décrit dans <a href="http://blog.developpez.com/wichtounet?title=concevoir_une_application_modulaire_base">le premier billet</a> en quoi consistait une <strong>application modulaire</strong> et ce qu&rsquo;était un module, nous allons maintenant nous pencher plus spécialement sur les <strong>modules</strong>. </p>
<p>Nous avons dit qu&rsquo;un module permettait de rajouter des fonctionnalités à l&rsquo;application principale. Mais avant de se lancer dans le moindre code, il va falloir définir exactement ce que seront nos modules, ce qu&rsquo;ils pourront faire, s&rsquo;il y aura plusieurs types de modules, &#8230;</p>
<p>C&rsquo;est ce que nous allons voir dans ce billet. </p>
<p><span id="more-113"></span></p>
<p>La première question à se poser est : &laquo;&nbsp;Que vont pouvoir faire mes modules ?&nbsp;&raquo;. C&rsquo;est-à-dire, qu&rsquo;est-ce qu&rsquo;un module pourra ajouter à l&rsquo;application principale. </p>
<p>Nous avons dit qu&rsquo;un module rajoutait des fonctionnalités à l&rsquo;application principale, mais il faut maintenant spécifier ce que les modules pourront ajouter et la manière dont ils vont pouvoir les ajouter. En plus d&rsquo;ajouter, un module pourra éventuellement modifier l&rsquo;application principale. </p>
<p>Ce que les modules pourront faire va dépendre également du type d&rsquo;application modulaire : </p>
<ul>
<li>Dans le cas du premier type (application normale avec possibilité d&rsquo;extension par module), le module va rajouter des fonctionnalités de types spécifiques, c&rsquo;est-à-dire en accord avec l&rsquo;application. Prenons le cas d&rsquo;une application qui permet de regarder la télévision via internet. Dans ce cas-là, les modules pourront par exemple rajouter une chaîne à l&rsquo;application ou rajouter un format de conversion vidéo pour l&rsquo;enregistrement. Il peut aussi rajouter une fonctionnalité complète comme des statistiques qui indiqueraient le nombre d&rsquo;heures pendant lesquelles on a regardé la télé sur ce programme et la chaîne la plus regardée. </li>
<li>Dans le cas du second type (application vide de base et modules qui rendent l&rsquo;application utilisable), les modules ne vont pas rajouter des fonctionnalités à l&rsquo;application principale étant donné qu&rsquo;elle ne permet rien, mais vont définir ce que va faire l&rsquo;application. Cette fois, les modules, c&rsquo;est l&rsquo;application. Prenons mon application (JTheque) qui est destiné à gérer des collections diverses. J&rsquo;ai pour le moment un module Films et un module Livres. J&rsquo;ai ensuite des plus petits modules comme le modules Stats ou un module qui permet de gérer une liste de films à acheter. On voit qu&rsquo;on a déja des modules beaucoup plus large. En plus, avec quelque chose de ce type, on pourrait imaginer une module qui ferait quelque chose de complètement différent de l&rsquo;application de base, comme un module Calculette qui ajouterait une calculatrice à l&rsquo;application, ce qui n&rsquo;est pas du tout le but de l&rsquo;application de base mais qui est rendue possible par les possibilités d&rsquo;extension du coeur de l&rsquo;application. </li>
</ul>
<p>Dans ces deux cas, il faut donc définir certains points d&rsquo;extension. Dans le cas de JTheque, voici les points d&rsquo;extension que j&rsquo;ai créé pour mes modules : </p>
<ul>
<li>Rajouter des onglets dans la vue principale</li>
<li>Rajouter des composants dans la barre d&rsquo;état</li>
<li>Rajouter des éléments dans le menu de la vue principale</li>
<li>Rajouter des onglets dans la vue de configuration</li>
</ul>
<p>A partir de ces points d&rsquo;extension, les modules peuvent faire beaucoup de choses. Par exemple, si on veut faire une calculette, on peut imaginer rajouter un onglet principal avec une calculette, ou alors faire une fenêtre dediée et rajouter un élément dans le menu qui ouvrirait cette fenêtre. </p>
<p>Ceci est donc laissé au libre choix du développeur, mais il faut y penser avant et bien réfléchir à ce que ça implique. </p>
<p>En plus de points d&rsquo;extension, le coeur de l&rsquo;application fournit aussi une série de services aux modules. Ces services peuvent être de simples classes utilitaires ou alors un gestionnaire de persistence d&rsquo;entités, un gestionnaire de log ou encore un gestionnaire permettant aux modules d&rsquo;enregistrer des informations pour les retrouver après l&rsquo;arrêt de l&rsquo;application. </p>
<p>Là encore ces points sont laissés à la discrétion du développeur. Ces services ne sont pas obligatoires, mais cela permet d&rsquo;éviter que chaque module doivent tout refaire. En plus, cela permet également une standardisation. En effet, les modules vont (normalement) utiliser le même type de persistence, le même type de log, &#8230; Ce qui est plus facile à gérer ensuite. Bien entendu, rien n&rsquo;empêche un module d&rsquo;utiliser son propre système de log si celui du coeur ne lui convient pas. </p>
<p>Pour la petite histoire, voilà les services que j&rsquo;offre à mes modules : </p>
<ul>
<li>Gestionnaire de logs : Permet aux modules d&rsquo;obtenir des loggers (Log4J) pour logger différentes actions. </li>
<li>Gestionnaire d&rsquo;erreurs : Permet aux modules d&rsquo;afficher des erreurs facilement</li>
<li>Gestionnaire de vue : Permet aux modules d&rsquo;afficher des messages, de demander quelque chose à l&rsquo;utilisateur, &#8230;</li>
<li>Gestionnaire de beans : Permet aux modules d&rsquo;utiliser de l&rsquo;IOC (Spring). </li>
<li>Gestionnaire de ressources : Permet aux modules de bénéficier de l&rsquo;internationalisation (Spring) ainsi que d&rsquo;un cache d&rsquo;image</li>
<li>Gestionnaire de persistence : Permet aux modules de gérer des entités persistentes (JPA/Hibernate). </li>
<li>Gestionnaire d&rsquo;états : Permet aux modules de stocker des états. </li>
</ul>
<p>On peut aussi réfléchir si on veut un seul type de module ou s&rsquo;il y en aura plusieurs. Dans mon cas, j&rsquo;ai fait une petite distinction entre des modules dits principaux et des modules dits secondaires. Les fonctionnalités sont exactement les mêmes sauf qu&rsquo;un seul module principal peut être lancé en même temps. Par exemple, le module films est un module principal et le module ajoutant une liste de films à acheter est un module secondaire. </p>
<p>Le dernier point que je vois à traiter au niveau des modules est la dépendance entre modules. On peut permettre ou non qu&rsquo;un module dépende d&rsquo;un autre module. Cela ajoute un niveau de difficulté supplémentaire au niveau de l&rsquo;implémentation étant donné qu&rsquo;il faudra vérifier que la dépendance est remplie avant de pouvoir lancer le module. Cela implique également que le module principal doit être lancé avant le module qui en dépent. Et que faire des dépendances circulaires ? Bref, cela est également laissé au choix du développeur qui peut permettre les dépendances intra-modules ou non. Dans mon cas, je l&rsquo;ai permis, j&rsquo;ai par exemple, le module Stats qui dépend du module Films étant donné qu&rsquo;il a besoin des informations sur les films, acteurs et réalisateurs pour générer ses statistiques. </p>
<p>Voilà, j&rsquo;en ai fini (enfin, me direz-vous ^^) avec les caractéristiques des modules. Comme pour le premier article, n&rsquo;hésitez surtout pas à vous manifester si vous avez des questions ou si vous n&rsquo;êtes pas d&rsquo;accord avec quelque chose que j&rsquo;ai dit ou si vous aimeriez plus d&rsquo;informations sur un point spécifique <img src="https://blog.developpez.com/wichtounet/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Concevoir une application modulaire &#8211; Implémentation</title>
		<link>https://blog.developpez.com/wichtounet/p6494/perso/concevoir_une_application_modulaire_impl</link>
		<comments>https://blog.developpez.com/wichtounet/p6494/perso/concevoir_une_application_modulaire_impl#comments</comments>
		<pubDate>Wed, 01 Oct 2008 23:50:01 +0000</pubDate>
		<dc:creator><![CDATA[Baptiste Wicht]]></dc:creator>
				<category><![CDATA[Conception]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JTheque]]></category>
		<category><![CDATA[Mes projets]]></category>
		<category><![CDATA[Perso]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Maintenant que nous avons vu en détails les caractéristiques des modules, nous allons voir comment mettre en oeuvre un module. Il nous faut donc un conteneur pour notre module qu&#8217;on puisse ensuite charger depuis notre application principale. Nous allons maintenant voir ce que sera un module au niveau Java. Comme un module est complètement indépendant de l&#8217;application principale, on ne peut inclure directement le module dans l&#8217;application principale, il faut distinguer le fichier du module [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Maintenant que nous avons <a href="http://blog.developpez.com/wichtounet?title=concevoir_une_application_modulaire_modu">vu en détails</a> les caractéristiques des modules, nous allons voir comment mettre en oeuvre un module. </p>
<p>Il nous faut donc un conteneur pour notre module qu&rsquo;on puisse ensuite charger depuis notre application principale. </p>
<p>Nous allons maintenant voir ce que sera un module au niveau Java. </p>
<p><span id="more-114"></span></p>
<p>Comme un module est complètement indépendant de l&rsquo;application principale, on ne peut inclure directement le module dans l&rsquo;application principale, il faut distinguer le fichier du module de celui de l&rsquo;application principale. </p>
<p>Il faut maintenant définir ce que vont être ces fichiers. Comme est au niveau Java, on peut s&rsquo;imaginer les modules comme des extensions de l&rsquo;application principale. Or pour étendre une application Java, on utilise des fichiers Jars. </p>
<p>Nos modules seront donc contenus dans des fichiers Jars. </p>
<p>Voici pour ce qui est de la manière de représenter physiquement un module, nous allons voir comment le représenter pour qu&rsquo;il soit utilisable au niveau Java. </p>
<p>Nous allons donc créer une interface permet de décrire les caractèristiques principales d&rsquo;un module. Nous allons rester simple pour le moment. Un module doit tout d&rsquo;abord être rattachable et ensuite détachable. C&rsquo;est-à-dire le moment ou il va se rattacher à l&rsquo;application, c&rsquo;est-à-dire l&rsquo;étendre et le moment où il va se détacher de l&rsquo;application. En plus de cela, un module a aussi un nom. Pour le moment, ce sera tout ce dont on a besoin. </p>
<p>On va donc avoir une interface tout simple décrivant notre module :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public interface IModule { <br />
&nbsp; &nbsp;public void plug(); <br />
&nbsp; &nbsp;public void unplug(); <br />
&nbsp; &nbsp;public String getName(); <br />
}</div></div>
<p>On pourrait donc créer un module très simple affichant quelque chose sur la console :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">package org.modules.simple; <br />
&nbsp;<br />
public class SimpleModule implements IModule { <br />
&nbsp; &nbsp;public void plug(){ <br />
&nbsp; &nbsp; &nbsp; System.out.println(&quot;Hello kernel !&quot;); <br />
&nbsp; &nbsp;} <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp;public void unplug(){ <br />
&nbsp; &nbsp; &nbsp; System.out.println(&quot;Bye kernel !&quot;); <br />
&nbsp; &nbsp;} <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp;public String getName(){ <br />
&nbsp; &nbsp; &nbsp; return &quot;Simple module&quot;; <br />
&nbsp; &nbsp;} <br />
}</div></div>
<p>Nous allons donc créer un fichier Jar contenant notre classe. </p>
<p>Il faut maintenant une solution pour que l&rsquo;application principale connaisse cette classe pour la lancer. Il faut donc un moyen pour qu&rsquo;elle trouve cette classe. </p>
<p>On pourrait imaginer parcourir le fichier jar et tester pour chacun des classes si c&rsquo;est un module ou non. Cette méthode bien que fonctionnelle n&rsquo;est pas du tout optimale car elle implique de parcourir toute l&rsquo;archive ce qui risque de prendre du temps dans le cas de gros module. Alors, on va utiliser les outils que nous offre Java et ajouter une mention dans le manifest du jar pour indiquer à l&rsquo;application principale quelle est la classe du module à charger. </p>
<p>Voilà à quoi ressemblerait notre Manifest pour notre petit module :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Manifest-Version: 1.0 <br />
Module-Class: org.modules.simple.SimpleModule</div></div>
<p>Cela permettra à l&rsquo;application principale de savoir quelle classe charger. </p>
<p>Je montrerai dans mon prochain billet une manière de charger ces modules. Car il ne suffit pas de mettre ces fichiers jars dans le classpath pour les charger étant donné que l&rsquo;application principale ne doit pas connaître les modules. </p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Concevoir une application modulaire &#8211; Chargement</title>
		<link>https://blog.developpez.com/wichtounet/p6535/jtheque/concevoir_une_application_modulaire_char</link>
		<comments>https://blog.developpez.com/wichtounet/p6535/jtheque/concevoir_une_application_modulaire_char#comments</comments>
		<pubDate>Wed, 08 Oct 2008 11:08:51 +0000</pubDate>
		<dc:creator><![CDATA[Baptiste Wicht]]></dc:creator>
				<category><![CDATA[Conception]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JTheque]]></category>
		<category><![CDATA[Mes projets]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Maintenant que nous avons vu comment représenter un module au niveau Java, nous allons voir comment charger dynamiquement ces modules dans notre application. Au niveau de Java, les classes sont chargées depuis des ClassLoader qui comme son nom l&#8217;indique est un chargeur de classes. De base, Java utilise le ClassLoader système pour charger les classes dont notre application a besoin et ce ClassLoader contient les classes de notre application et toutes les classe qu&#8217;il a [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Maintenant que <a href="http://blog.developpez.com/wichtounet?title=concevoir_une_application_modulaire_impl">nous avons vu </a>comment représenter un module au niveau Java, nous allons voir comment charger dynamiquement ces modules dans notre application. </p>
<p>Au niveau de Java, les classes sont chargées depuis des ClassLoader qui comme son nom l&rsquo;indique est un chargeur de classes. </p>
<p><span id="more-7"></span></p>
<p>De base, Java utilise le ClassLoader système pour charger les classes dont notre application a besoin et ce ClassLoader contient les classes de notre application et toutes les classe qu&rsquo;il a pu découvrir dans le classpath qu&rsquo;on lui a fourni. </p>
<p>Le problème est que dans notre cas, on ne peut pas vraiment ajouter les fichiers Jar des modules au classpath étant donné que l&rsquo;application ne connait pas les modules. </p>
<p>De plus, on ne peut théoriquement pas modifier le ClassLoader système. Je dis théoriquement, parce qu&rsquo;il est possible de rajouter des fichiers ou des ressources à un ClassLoader en utilisant la réfléction et en appelant une méthode non publiques, mais je ne trouve que cette méthode soit très propre. </p>
<p>Nous allons donc devoir créer un nouveau ClassLoader avec lequel nous allons charger les classe de nos modules. </p>
<p>Il nous faudra donc procéder en deux phases : </p>
<ul>
<li>La première servira à explorer les fichiers des modules, à en sortir la classe du module et à récolter les URLs des fichiers Jar</li>
<li>La seconde va charger les différents modules en se servant d&rsquo;un ClassLoader créé avec les URLs collectées durant la première phase. </li>
</ul>
<p>On va donc créer une classe ModuleLoader qui va nous permettre d&rsquo;effectuer ces phases. </p>
<p>Prenons maintenant la première phase et créons une méthode qui retourne la liste des classes à charger.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">public class ModuleLoader { <br />
&nbsp; &nbsp; private static List&lt;URL&gt; urls = new ArrayList&lt;URL&gt;(); <br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; private static List&lt;String&gt; getModuleClasses(){ <br />
&nbsp; &nbsp; &nbsp; List&lt;String&gt; classes = new ArrayList&lt;String&gt;(); <br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; //On liste les fichiers de module &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; File[] files = new File(&quot;dossier&quot;).listFiles(new ModuleFilter()); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; for(File f : files){ <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; JarFile jarFile = null; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //On ouvre le fichier JAR <br />
&nbsp; &nbsp; &nbsp; &nbsp; jarFile = new JarFile(f); <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; //On récupère le manifest <br />
&nbsp; &nbsp; &nbsp; &nbsp; Manifest manifest = jarFile.getManifest(); <br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; //On récupère la classe <br />
&nbsp; &nbsp; &nbsp; &nbsp; String moduleClassName = manifest.getMainAttributes().getValue(&quot;Module-Class&quot;); <br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; classes.add(moduleClassName); <br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; urls.add(f.toURI().toURL()); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (IOException e) { <br />
&nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace(); <br />
&nbsp; &nbsp; &nbsp; } finally { <br />
&nbsp; &nbsp; &nbsp; &nbsp; if(jarFile != null){ <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jarFile.close(); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (IOException e) { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace(); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; return classes; <br />
&nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; private static class ModuleFilter implements FileFilter { <br />
&nbsp; &nbsp; @Override <br />
&nbsp; &nbsp; public boolean accept(File file) { <br />
&nbsp; &nbsp; &nbsp; return file.isFile() &amp;&amp; file.getName().toLowerCase().endsWith(&quot;.jar&quot;); <br />
&nbsp; &nbsp; } <br />
&nbsp; &nbsp; } <br />
}</div></div>
<p>Comme vous le voyez, ce n&rsquo;est pas très compliqué, on parcours les fichiers Jar existant dans le dossier des modules, on ouvre le fichier Jar, on récupère le manifest et on récupère la classe du module. Ensuite de quoi, on ajoute encore l&rsquo;URL du fichier Jar à la liste des URLs. </p>
<p>Bien entendu ce code est perfectible, il faudrait traiter le cas ou le fichier JAR n&rsquo;a pas de manifest ou alors le cas ou le manifest n&rsquo;a pas de classe de module et il faudrait traiter les erreurs correctement, mais ce n&rsquo;est pas le but de ce billet. </p>
<p>On peut maintenant passer à la deuxième méthode qui va créer le ClassLoader et instancier les modules puis les retourner :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">private static ClassLoader classLoader; <br />
&nbsp;<br />
public static List&lt;IModule&gt; loadModules(){ <br />
&nbsp; List&lt;IModule&gt; modules = new ArrayList&lt;IModule&gt;(); <br />
&nbsp; <br />
&nbsp; List&lt;String&gt; classes = getModuleClasses(); <br />
&nbsp; <br />
&nbsp; AccessController.doPrivileged(new PrivilegedAction&lt;Object&gt;(){ <br />
&nbsp; &nbsp; @Override <br />
&nbsp; &nbsp; public Object run() { <br />
&nbsp; &nbsp; &nbsp; classLoader = new URLClassLoader( <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; urls.toArray(new URL[urls.size()]), &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ModuleLoader.class.getClassLoader()); <br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; return null; <br />
&nbsp; &nbsp; } <br />
&nbsp; }); <br />
&nbsp; <br />
&nbsp; for(String c : classes){ <br />
&nbsp; &nbsp; try { <br />
&nbsp; &nbsp; &nbsp; Class&lt;?&gt; moduleClass = Class.forName(c, true, classLoader); <br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; if(IModule.class.isAssignableFrom(moduleClass)){ <br />
&nbsp; &nbsp; &nbsp; &nbsp; Class&lt;IModule&gt; castedClass = (Class&lt;IModule&gt;)moduleClass; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; IModule module = castedClass.newInstance(); <br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; modules.add(module); <br />
&nbsp; &nbsp; &nbsp; } &nbsp;<br />
&nbsp; &nbsp; } catch (ClassNotFoundException e1) { <br />
&nbsp; &nbsp; &nbsp; e1.printStackTrace(); <br />
&nbsp; &nbsp; } catch (InstantiationException e) { <br />
&nbsp; &nbsp; &nbsp; e.printStackTrace(); <br />
&nbsp; &nbsp; } catch (IllegalAccessException e) { <br />
&nbsp; &nbsp; &nbsp; e.printStackTrace(); <br />
&nbsp; &nbsp; } <br />
&nbsp; } <br />
&nbsp; <br />
&nbsp; return modules; <br />
}</div></div>
<p>On commence donc créer un nouveau ClassLoader à partir des URLs qu&rsquo;on a récupéré avec les fichiers JARs. On va utiliser un URLClassLoader qui permet de charger des classes depuis des emplacements définis par des URLs. On va lui donner comme parent le ClassLoader de la classe. Comme cela les modules qui utiliseront ce classloader pourront également utiliser les classes de l&rsquo;application, ce qui est le but d&rsquo;une application modulaire. Une fois qu&rsquo;on a créé notre ClassLoader, on va parcourir toutes nos classes et les instancier si elles implémentent bien la bonne interface. Ensuite, on va pouvoir les ajouter à la liste et les retourner. </p>
<p>Encore une fois, ce code est perfectible, il faudrait traiter les erreurs et réagir aux différents cas possibles, mais j&rsquo;ai essayé de faire au plus court. </p>
<p>Notre chargeur de modules est donc terminé. </p>
<p>Nous pouvons tester notre application en créant un Jar pour le module que nous avons défini dans le billet précédent et en créant un code tout simple pour les charger :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">List&lt;IModule&gt; modules = ModuleLoader.loadModules(); <br />
&nbsp;<br />
for(IModule module : modules){ <br />
&nbsp; System.out.println(&quot;Plug : &quot; + module.getName()); <br />
&nbsp; module.plug(); <br />
} <br />
&nbsp;<br />
System.out.println(&quot;Déroulement de l'application. &quot;); <br />
&nbsp;<br />
for(IModule module : modules){ <br />
&nbsp; module.unplug(); <br />
}</div></div>
<p>Voici ce que rendrait l&rsquo;éxécution : </p>
<blockquote><p>Plug : Simple module<br />
Hello kernel !<br />
Déroulement de l&rsquo;application.<br />
Bye kernel !</p></blockquote>
<p>Comme vous le voyez, nous venons de développer une application modulaire. Bien entendu, il faut ensuite développer tous les services et les points d&rsquo;extension, mais ces points sont spécifiques à l&rsquo;application. </p>
<p>La technique présentée dans ce billet pose néanmoins un problème pour ce qui est du déploiement à la volée de module. En effet, si on charge un module après le chargement des premiers modules, on devra recréer un nouveau ClassLoader et on aura donc une partie des modules dans le premier ClassLoader et une partie des modules dans le second ClassLoader. Néanmoins, si les modules n&rsquo;ont aucune intéraction entre eux, vous pouvez tout à fait envisager cette méthode pour le déploiement à la volée. Si ce n&rsquo;est pas le cas, vous serez obligé de vous rabattre sur la méthode avec réfléction pour ajouter des modules dans votre ClassLoader. Je présenterai peut-être cette méthode dans un prochain billet. </p>
<p>Le fait d&rsquo;avoir un deuxième ClassLoader pose également un problème pour les librairies qui chargent des classes à la volée comme par exemple Spring IOC ou Hibernate. Il faut voir au cas par cas pour ces librairies comment on peut leur spécifier d&rsquo;utiliser notre ClassLoader. Souvent ceci est faisable en spécifiant le contextClassLoader via la méthode <em>Thread.currentThread().setContextClassLoader(ClassLoader cl)</em>.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
