• Aucun résultat trouvé

Chapitre 8 Introspection, reconfiguration & extensibilité

3. Support des composants atomiques

La section précédente a décrit globalement comment étaient implémentés les concepts de base d’iPOJO. Cette section s’attarde sur les composants atomiques implémentés en Java. Plusieurs points seront abordés tels que la machine d’injection et d’introspection (dont les fonctionnalités ont été décrites auparavant dans cette thèse), la gestion du dynamisme et de la synchronisation ainsi que les autres fonctionnalités fournies.

Clement Escoffier 154

3.1. Implémentation de la machine d’injection

Afin de proposer un modèle de développement à la fois simple et puissant, cette thèse a décrit les fonctionnalités que devait fournir la chaine d’injection et d’introspection sous-jacente. Cette machine a été implémentée pour Java sous la forme d’une manipulation de bytecode.

En effet, le manipulateur inclus dans iPOJO transforme une classe en une classe manipulée permettant l’interception des méthodes et des accès aux membres (champs de la classe) . De plus cette manipulation a la particularité de lier la classe manipulée au conteneur d’iPOJO en y ajoutant des méthodes d’initialisation. Ainsi, le conteneur pourra injecter des valeurs dans des membres, en connaitre la valeur actuelle, mais pourra également invoquer des méthodes. Plusieurs contraintes sont apparues durant le développement de cette machine : l’extensibilité et la capture de référence.

Tout d’abord, afin de supporter l’extensibilité, cette manipulation est générique. Ainsi pour une classe donnée, la classe obtenue après la manipulation sera la même. Les métadonnées ne sont pas examinées durant la manipulation. Bien que ce type de manipulation est considéré comme moins performant qu’une manipulation spécifique, elle a pour avantage d’abstraire la manipulation (les développeurs de handler n’ayant pas à la spécifier). De plus, le dynamisme ayant un impact non négligeable sur le code, le surcoût dû à cette manipulation est négligeable.

Enfin, il est crucial que la classe manipulée ne détienne pas de référence directe sur un objet de service. En effet, si cette classe se retrouvait avec une référence sur un objet de service, le fournisseur ne pourrait pas être déchargé intégralement lors de son départ. Ce problème est dû à la politique de déchargement de classe de la machine virtuelle Java. Ainsi, lorsqu’un membre de la classe est géré par le conteneur, ce champ ne reçoit jamais la référence sur l’objet injecté. Celui-ci n’est jamais assigné.

Figure 109. Illustration de la manipulation. La classe originale (à gauche) devient la classe manipulée (à droite) La figure ci-dessus montre un exemple de classe manipulée par rapport à une classe d’origine. Remarquons que les accès aux membres de la classe sont remplacés par des appels de méthodes (générés). Le

155 nom des méthodes d’origines est préfixé par « __ ». De plus, les méthodes sont encapsulées afin de permettre l’interception de l’entrée, de la sortie ainsi que des erreurs potentielles. La manipulation des méthodes prend soin de ne pas modifier les numéros de lignes (si la classe d’origine les contient) afin de ne pas influer sur les informations de débogage. La manipulation des membres permet au conteneur de toujours retourner une valeur à jour. Un mécanisme de drapeau est mis en place pour réduire le coût de délégation lorsque le conteneur ne surveille pas un membre ou une méthode (membres commençants par _F et _M). Il faut également noter que les membres, méthodes et blocs d’initialisation statiques ne sont pas manipulés.

La machine d’interception et d’introspection décrite dans cette thèse doit également fournir des fonctionnalités permettant d’appeler des méthodes. Ces appels sont effectués grâce à l’API de réflexion fournie par Java. Cependant, afin de masquer certaines complexités dues à l’utilisation de cette API dans un environnement dynamique, ces appels sont effectués grâce à une classe utilitaire (fournie par iPOJO) permettant de configurer des appels de méthodes et d’appeler ces méthodes sur les objets sous-jacents. Ainsi, les problèmes de synchronisation, d’appel sur plusieurs objets sont gérés par cette classe.

Figure 110. Conditionnement de composants iPOJO

Le manipulateur est implémenté à l’aide de la bibliothèque OW2 ASM [194, 195] qui permet de lire et de manipuler des classes Java. Cette manipulation est effectuée durant la phase de conditionnement du composant (Figure 110). Il aurait été possible d’effectuer cette manipulation lors du chargement. Cependant, OSGi™ ne définit pas de mécanismes permettant d’effectuer cette manipulation sans enfreindre les règles de sécurité. Ce type de mécanisme sera très probablement fourni dans les prochaines versions d’OSGi™. De plus, lors du conditionnement, la manipulation permet d’anticiper certains problèmes ainsi que de remonter des informations sur l’implémentation des composants. Ces informations servent principalement à retarder le chargement de classe à l’exécution (en effet, ceci évite généralement d’utiliser la réflexion simplement pour obtenir des informations sur la classe). Afin d’éviter l’utilisation d’une bibliothèque XML, les métadonnées sont transformées dans une syntaxe interne et sont ajoutées au manifeste du bundle.

Il existe aujourd’hui trois interfaces permettant de manipuler les composants Java. Un plug-in Eclipse permet de conditionner des bundles contenant des composants iPOJO directement à partir de l’IDE Eclipse. Une tâche Ant et un plug-in Maven permettent également d’intégrer des bundles iPOJO dans des processus de construction de projets plus complexes.

3.2. Gestion du dynamisme

Au-dessus de la machine d’injection décrite dans la section précédente, plusieurs handlers ont pour but de gérer le dynamisme, et particulièrement les interactions avec l’annuaire de service. Deux handlers sont particulièrement impliqués dans cette tâche : le handler de dépendance de service et le handler de fourniture de service (Figure 111).

Le handler de dépendance de service gère les services requis, c'est-à-dire la recherche et la sélection de fournisseurs de service, le maintien de la liaison (en fonction des politiques de liaison définies), ainsi que l’injection des objets de services (par l’intermédiaire de méthodes ou de membres de la classe d’implémentation du composant). Ce handler implémente l’intégralité du modèle de dépendance proposé dans

Clement Escoffier 156 cette thèse. Ainsi, une fois configuré et démarré, il traque les fournisseurs de service et sélectionne les fournisseurs. Il gère également la liaison. Lorsque cela est nécessaire, ce handler invalide l’instance (absence de fournisseurs, liaison cassée). Ce handler permet également de récupérer des informations sur les fournisseurs utilisés. Cette fonctionnalité est nécessaire durant l’introspection d’un système.

Figure 111. Les fonctionnalités d'iPOJO sont également développées sous la forme de handler

Le handler de fourniture de service a pour but de publier et de fournir des services. Celui-ci gère alors l’intégralité des interactions avec l’annuaire de service afin de gérer l’enregistrement de service. De plus, ce handler supervise des membres de la classe attachés à des propriétés de service afin de répercuter les éventuels changements de valeur.

Un aspect délicat dans l’implémentation de ces handlers est le support de la synchronisation et des reconfigurations. En effet, sachant que plusieurs fils d’exécution peuvent s’exécuter à l’intérieur d’une instance, et que les arrivées et départs de service utilisent également d’autres fils, il est nécessaire de gérer correctement tous ces paramètres. Ceci est crucial afin de reconfigurer les instances proprement. L’implémentation d’iPOJO n’attend pas la quiescence afin d’exécuter une reconfiguration. En effet, la politique d’iPOJO effectue les reconfigurations immédiatement. L’utilisation des caches associés aux différents fils d’exécution permet de garantir la cohérence du système. Ainsi, l’implémentation d’iPOJO utilise les concepts de confinement sur pile et de confinement par thread [184] afin d'effectuer les reconfigurations.

3.3. Autres handlers fournis

L’implémentation actuelle d’iPOJO fournit d’autres handlers. Le cœur d’iPOJO est livré avec un handler de cycle de vie (permettant de créer et de notifier des objets contenus lorsque l’instance devient valide ou invalide), un handler d’architecture utilisé lors de l’introspection du système, une handler de configuration permettant de configurer et de reconfigurer des instances dynamiquement, et un handler de contrôle de cycle de vie permettant au contenu d’une instance de participer au cycle de vie de l’instance.

De plus, plusieurs handlers externes ont également été développés. Ainsi, un handler d’administration par JMX permet d’administrer à distance des instances. Des handlers permettent également d’automatiser l’émission et la réception d’évènements. Un handler de persistance a également été développé et permet de stocker et de recharger l’état d’instance sur un support persistant. D’autres handlers permettent l’automatisation d’interactions complexes utilisant les motifs de conceptions de tableau blanc [196], ou d’extension.

D’autres handlers plus spécifiques ont également été développés afin d’ajouter de la qualité de service, ou des fonctionnalités autonomiques [188].

157