C.3 Génération de dispositifs d'application «à la volée»

La création dynamique de dispositifs n'est pas nouvelle dans ICON, en particulier pour les dispositifs système. En effet, la gestion de bon nombre des périphériques d'entrée est activée à l'exécution, et la création des dispositifs prototypes est alors dynamique.

Nous avons généralisé ce principe et ces mécanismes aux dispositifs génériques d'application, en particulier pour les manipulateurs d'objets graphiques de MAGGLITE (voir la section 7.4.2). Ces dispositifs, rappelons-le, sont des dispositifs d'instance (liés à un objet graphique particulier) qui permettent un contrôle direct d'un nœud du graphe de scène, externalisant alors les propriétés de cet objet dans le graphe d'interaction. Donc, lorsqu'un nouveau nœud est ajouté au graphe de scène, celui-ci peut, ou non, installer son manipulateur dans la librairie des dispositifs disponibles.

Le principe des manipulateurs, d'un point de vue technique, est d'associer un slot du manipulateur à un méthode de l'objet que l'on souhaite externaliser. Il aurait été fastidieux d'avoir à développer une classe de dispositifs ICON à chaque création d'une nouvelle classe d'objet graphique. Nous proposons donc un mécanisme utilisant les capacités d'introspection (réflection) du langage Java afin d'obtenir les méthodes de l'objet correspondantes aux slots à créer, de les invoquer sur l'objet lorsque le dispositif reçoit les signaux correspondants, et de les décrire à l'aide des annotations (metadata) spécifique à Java 5. Il suffit, lors du développement d'une nouvelle classe de nœuds du graphe de scène, de respecter les conventions de nommage que nous avons fixées afin que la boîte à outil crée le dispositif correspondant aux méthodes que nous avons nommées xmethods.

La figure C.9 présente sur un exemple les méthodes d'un objet associées à son dispositif. La méthode xcomVisible() est externalisée sous la forme d'un slot d'entrée booléen nommé visible, la méthode xsetMove(double dx, double dy) sous la forme de deux slots d'entrée de type double nommés move.dx et move.dy et enfin la méthode Object xgetId() sous la forme d'un slot de sortie de type Object.

Figure C.9: Correspondance objet/dispositif. Le dispositif d'application (un manipulateur de la boîte à outils MAGGLITE dans cet exemple) présente des slots associés aux méthodes du composant graphique dans cet exemple.
\includegraphics[width=400pt]{xmethods}

Cet exemple introduit trois catégories de xmethods:

  1. les méthodes de commande, déclarées sous la forme xcomNom(). La sémantique associée à ces méthodes est le déclenchement d'une action ou d'un comportement spécifique à l'objet. Elles ne prennent donc pas de paramètres en entrée et ne retournent aucune valeur. Elles seront présentées sur le dispositif sous la forme d'un slot booléen.
  2. les méthodes d'état, déclarées sous la forme xsetNom(type p[, type...]). Ces méthodes représentent des modificateurs d'états ou de propriétés de l'objet. Elle prennent donc autant de paramètres que nécessaire (de types compatibles avec le typage des slots de ICON) et n'ont pas de valeur de retour. Un slot d'entrée est donc créé pour chaque paramètre de la méthode, et ceux-ci sont groupés hiérarchiquement dans un groupe de slots portant le nom de la méthode.
  3. les méthodes d'émission, déclarées sous la forme type xgetNom(). Ces méthodes sont des accesseurs à des valeurs d'état ou d'attribut de l'objet, qui ne prennent pas de paramètres, mais doivent retourner une valeur (de type compatible avec le typage des slots de ICON). Ainsi, un slot de sortie est créé sur le dispositif.

Les méthodes de commande et d'état sont invoquées lorsque le ou les slots associés reçoivent un signal, les méthodes d'émission sont invoquées à chaque pas de l'exécution. Toutefois, ces appels aux méthodes de l'objet pose un problème de stratégie à employer dans le cas des méthodes d'état et dans le cas des méthodes d'émission.

Pour les méthodes d'état, il est clair qu'elle ne peuvent être invoquées si tous les paramètres ne sont pas définis, c'est à dire si tous les slots d'entrée correspondant du dispositif ne sont pas connectés, et n'ont pas tous reçu au moins une fois un signal. Mais lorsque tous les slots (et donc les paramètres de la méthode) ont une valeur, doit-on invoquer la méthode si tous les slots n'ont pas reçu de signal (et donc une potentielle nouvelle valeur) ?
Pour les méthodes d'émission, le problème est inverse. La méthode de l'objet est invoquée à chaque pas de l'exécution. Mais le dispositif doit-il émettre la valeur de retour de cette méthode à chaque pas, même si celle-ci n'a pas changée ?

À ces problèmes de stratégie, s'ajoute aussi le problème du nommage des slots, en particulier dans le cas des méthodes d'état. En effet, les mécanismes d'introspection de Java nomment les paramètres des méthodes en utilisant des caractères alphanumériques, quel que soit le nom qui leur avait été donné dans le code source. Ainsi, les slots correspondant à une méthode prenant trois paramètres seraient nommé a, b et c. Il faut bien avouer qu'un tel nommage serait un sérieux obstacle au paradigme de programmation visuelle d'ICON. De plus, il pourrait être intéressant de regrouper les slots de certaines méthodes selon la sémantique de ces méthodes.

Nous proposons une solution unifiée à ces problèmes qui va permettre au programmeur d'annoter les xmethods de l'objet, et donc de spécifier les noms et groupes des slots qu'il veut voir apparaître pour la méthode, ainsi que la stratégie souhaitée pour leur invocation. Nous avons utilisé pour cela le mécanisme des annotations (ou metadata) de Java 5 afin de permettre la construction de descripteurs de méthodes. Voici un exemple de descripteur pour la méthode d'état xsetMove de la figure C.9:

\begin{figure}\javafile[Exemple de déclaration d'une \protect\emph{xmethod}. Le ...
...méthode, de ses paramètres et la stratégie d'invocation.]{xmethods}
\end{figure}
Le descripteur de cet exemple, écrit juste avant la signature de la méthode, définit le nom qui sera donné à la méthode («move», ici), les noms de ses paramètres qui seront donc donné aux slots (préfixés par le nom de la méthode car nous somme dans le cas d'une méthode d'état) et la stratégie d'invocation de la méthode (lorsqu'au moins un des slots correspondant à la méthode a reçu un signal). Avec la valeur Vrai, ce descripteur allSignals signifierait qu'il faut que tous les slots aient reçus un signal au même pas d'exécution pour invoquer la méthode.

L'exemple ci-après présente le champ de descripteur permettant de grouper des slots associés à différentes méthodes:

\begin{figure}
% latex2html id marker 8801
\javafile[Exemple de déclaration de \...
...itif correspondant figure
\protect\ref{fig:xmethods1}).]{xmethods1}
\end{figure}
Le champ methodGroup permet dans ce cas de préfixer le nom des méthodes avec ce nom de groupe. Cela entraîne la création d'un groupe de slots, permettant de regrouper les slots correspondants à des méthodes de même sémantique. La figure C.10 présente le résultat du code précédent.

Figure C.10: Groupement de slots avec les descripteurs de méthodes. Les slots d'entrée créés lors de l'introspection sur les méthodes de l'exemple de code C.3 sont regroupés dans le groupe «interpolation» grâce à l'attribut methodGroup.
\includegraphics[width=150pt]{xmethods1}

Globalement, l'architecture de la boîte à outil encourage la réutilisation des composants existants et l'implémentation des interfaces fournies afin de maintenir une cohérence au niveau des manipulateurs d'objets présentant des propriétés ou interfaces communes. Par exemple, tout objet graphique héritera des propriétés de l'objet de base «MaggLite». De ce fait, sont manipulateur présentera automatiquement les slots d'entrée (visible et label) et de sortie (id) communs à tous les objets de la classe MaggLite. Mais c'est aussi à ce niveau que peuvent être définies des xmethods de manière abstraite. Un composant conçu pour pouvoir être redimensionné implémentera une interface de la boîte à outil nommée « Sizeable». Cette interface impose l'implémentation de la méthode «xsetResize(double x, double y)» afin que tous les manipulateurs d'objets ayant cette capacité présente les slots d'entrée correspondants, de manière unifiée. Ainsi, un concepteur d'interfaces ou un utilisateur final retrouvera toujours les mêmes slots pour des capacités identiques (voir figure C.11).

Figure C.11: Détail d'un manipulateur. Ce manipulateur a été généré automatiquement pour contrôler un composant graphique conteneur d'image. Chaque classe héritée ou interface instanciée par le composant fournit des méthodes qui sont alors externalisées sous forme de slots d'entrée ou de sortie par le mécanisme de génération des manipulateurs lors de l'instanciation d'un objet. Les slots propres à la classe de l'objet (MaggLiteImage) sont désignés ici en rouge.
\includegraphics[width=400pt]{manipulatordetail}

Ce mécanisme de génération automatique de dispositifs permet de de ne pas se soucier de la programmation des dispositifs ICON lors de la création des objets de l'application que l'on veut externaliser. La notion de xmethods, associées à leurs descripteurs, permet un contrôle assez poussé sur les dispositifs générés, bien que n'offrant pas encore un accès à toutes les possibilités des dispositifs ICON (slots de type variant, contrôle plus spécifique des signaux reçus ou émis, paramètres de dispositifs). Il est envisageable de rendre les descripteurs plus précis et adaptés, mais nous pensons alors qu'il serait plus efficace de développer un dispositif de manière traditionnelle (ce que nous avons fait avec les autres dispositifs génériques d'application dans MAGGLITE: Dispositifs d'interaction, Outils internes et Comportements).

stuf
2005-09-06