• Aucun résultat trouvé

programma-public aspect Program {

public int Counter.count;

class State implements Lib.State { private int count;

public State() {}

void setCounter (int x) { count = x; } int getCounter() { return count; } }

// Modification de la variable pointcut set_count():

set(int Counter.count);

void around (int count, Counter obj): set_count() && args(count) && target(obj) { obj.state.setCounter(count)

}

// Accès à la variable pointcut get_count():

get(int Counter.count);

int around (Counter obj): get_count() && target(obj) { return obj.state.getCounter();

} }

Fig. 8.8 Aspect correspondant à la facette programme

tion orientée aspect de générer la totalité du code nécessaire à l'implémentation du service. Elle a comblé au niveau de la représentation abstraite les détails manquants liés à l'environnement, au langage et au programme. Pour être applicable correctement, l'ordre d'insertion des aspects est toutefois important. Par exemple, certains greons dé-nissent des entités qui sont manipulées par des parties de code d'un autre aspect. Pour résoudre ce problème, l'AOP permet de dénir des relations de précédence entre aspects an de déterminer l'ordre d'exécution des greons. Notre approche par décomposition en facettes s'insère complètement dans cette démarche puisque l'ordre d'insertion re-ète le niveau de spécicité du code à introduire (environnement, puis langage et enn programme).

La modularité introduite par la programmation orientée aspect permet entre autres de limiter les eets d'une évolution de l'API de programmation sur la compilation. En eet, en localisant le code à introduire dans des aspects bien dénis, il sut de propager la modication au niveau du greon qui se répercutera automatiquement à de multiples endroits dans le code (e.g., l'envoi de requêtes).

8.5.1 Facette environnement d'exécution

La spécialisation de programme peut être appliquée au niveau de la facette environ-nement d'exécution an d'optimiser le processus de compilation. Cette technique est, en eet, souvent utilisée avec succès pour personnaliser un environnement d'exécution selon un contexte d'utilisation particulier. Dans notre cas, la plate-forme JAIN SIP est res-ponsable de l'invocation de méthodes spéciques dans la représentation abstraite pour le traitement des requêtes et des réponses. Lorsqu'aucune méthode n'est dénie dans le programme (e.g., absence du gestionnaire handler REGISTER ou handler INVITE), la plate-forme n'a pas besoin de transférer le message SIP au service. À la place, il est possible d'accomplir le comportement par défaut de la plate-forme. Un tel ltrage des messages est similaire au ltrage de paquets en réseau, où seuls certains paquets sont transmis à la couche applicative. La spécialisation de programme a déjà été appliquée dans ce contexte [TCL+00] et a démontré ses bénéces. Dans notre exemple, une stra-tégie similaire vise à spécialiser le ltrage des messages de la plate-forme JAIN SIP par rapport aux noms des requêtes présentes dans la représentation abstraite.

Cette approche permet de spécialiser systématiquement et automatiquement les composants logiciels génériques, comme la plate-forme JAIN SIP, selon un contexte de personnalisation dérivé de la représentation abstraite, et donc du service SPL.

8.5.2 Facette langage

Chander et al. [CEI+05] ont récemment proposé une approche de contrôle de res-sources. Leur approche contraint l'utilisation de ressources par rapport à une politique spéciant ce que le programme peut utiliser et les limites d'utilisation correspondantes.

L'idée clé est d'assurer que pour chaque opération consommant des ressources, une quan-tité susante est toujours disponible. Ils proposent pour cela d'annoter un programme avec une commande consume e spéciant que e unités de ressources sont utilisées, et avec une commande reserve e pour spécier que e unités doivent être réservées. L'un des avantages de cette approche est de rendre possible l'utilisation d'un prouveur de théorèmes pour assurer que les vérications adéquates sont réalisées an de garantir une utilisation correcte des ressources pour un programme donné. Leur véricateur est composé de deux composants : un générateur de conditions de sûreté qui extrait des prédicats logiques dont la validité implique la sûreté de l'utilisation des ressources et un prouveur qui prouve les prédicats.

La gure 8.9 illustre l'application de cette approche à la compilation de la facette non-fonctionnelle langage. Elle permet d'introduire de la gestion de ressources au sein de notre programme. La partie gauche de la gure montre un programme SPL où une liste d'appelants callers est dénie, spéciant les trois personnes qui sont autorisées à contacter le propriétaire du service. Si l'appelant n'est pas autorisé, l'appel est redirigé sur une liste de quatre opérateurs operators jusqu'à ce que l'un d'entre eux décroche.

La représentation abstraite correspondante est représentée sur la partie droite de la gure.

Dans le domaine de la téléphonie, l'action de transfert d'appel représente une

res-[...]

public void processRequest (RequestEvent requestEvent) { String method = rq_request.getMethod();

if (method.equals (Request.INVITE)) {

if (lib.registrar.hasRegistration (rq_request)) { //@ reserve 4

Header from_h = rq_request.getHeader(FromHeader.getName());

String FROM = from_h.getDisplayName();

int i = 0;

int size = callers.size();

while (i < size) {

String caller = (String) callers.get(i);

if (FROM.equals(caller)) { //@ consume 1

sendRequest(false, rq_request);

return;

} i++;

}

//@ inv(i <= 3, 3 - i) //@ consume 4

sendRequest(false, operators, rq_request);

return;

} [...]

} }

[...]

service limit_forward { processing {

uri<4> operators = < ... >;

uri<3> callers = < ... >;

registration { dialog {

response incomingINVITEINVITE(){ foreach (caller in callers) {

if (FROM == caller) { return forward;

} }

return forward operators;

} } } } }

Fig. 8.9 Annotations correspondantes à la facette langage

source clé parce qu'elle déclenche une chaîne d'opérations qui peuvent être coûteuses pour la plate-forme. Il peut donc apparaître intéressant de considérer cette action comme une ressource et de contrôler son utilisation. Pour cela, les opérations de routage de la représentation abstraite ont été annotées (consume), ainsi que les boucles, avec l'inser-tion d'un invariant inv(i ≤3, 3−i) qui indique que le prédicat i ≤3 doit toujours être vrai et qu'au moins3−i unités de ressources doivent être disponibles. À travers une analyse d'annotations, nous pouvons déterminer que cet exemple nécessite, au pire, la réservation de quatre unités de ressources (reserve 4), correspondant au cas où aucun opérateur ne peut prendre l'appel. Ainsi, nous pouvons assurer que susamment de res-sources ont été réservées avant l'exécution du programme. Notons que nos annotations consume sont rendues explicites dans la représentation abstraite, mais qu'elles peuvent être aussi bien incorporées dans une librairie en étendant l'API JAIN SIP existante.

Cet exemple illustre l'utilisation de traitements non-fonctionnels sur la représenta-tion abstraite. Ainsi, la véricareprésenta-tion de limites de ressources est introduite par réutilisa-tion d'un langage d'annotaréutilisa-tions et d'outils existants [CEI+05]. Ce faisant, le dévelop-peur du compilateur de DSL est guidé par le langage d'annotations pour déterminer les informations non-fonctionnelles requises dans le programme abstrait. De plus, les anno-tations permettent une modularisation du compilateur et une spécication des tâches, dans la mesure où leur traitement est réalisé indépendamment par un prouveur existant.

8.5.3 Facette programme

Contrairement à la facette fonctionnelle programme qui dénit des traitements du compilateur spéciques à un programme donné, la facette non-fonctionnelle programme

correspond à des traitements d'informations collectées sur ce programme. Si nous consi-dérons l'exemple de la gure 8.9, une extension de l'approche par annotations pourrait collecter les annotations reserve pour chaque gestionnaire SPL, an de calculer le nombre maximum d'opérations de routage accomplies par le programme. Ce nombre pourrait ensuite être utilisé par une politique de sécurité de l'environnement d'exécu-tion. Ce faisant, certaines restrictions pourraient être appliquées sur le nombre d'opé-rations de routage réalisées par un service SPL, an de préserver les performances de la plate-forme. Cette application peut être faite avant l'exécution du programme par rapport aux ressources actuellement disponibles. Ce processus peut être perçu comme un contrôle d'admission. Cette approche pourrait être étendue à toutes les ressources consommées par le programme. Ainsi, un service de téléphonie serait accompagné d'une liste de ressources nécessaires à son exécution.

Notons que cette facette programme est diérente de la facette langage présentée précédemment. En eet, la facette langage n'adresse pas la consommation de ressources de manière globale au service ; elle assure seulement que la ressource consommée a été auparavant allouée.

Un problème important du domaine de la téléphonie concerne la facturation. Il est tout à fait possible de prendre en compte cette problématique au niveau d'une facette non-fonctionnelle programme En examinant le type de traitements de compilation à réaliser pour introduire des opérations de facturation, nous pouvons noter que cette stratégie équivaut à introduire des aspects non-fonctionnels, analogues aux activités de monitorage (e.g., logging). Par exemple, des minuteurs pourraient être déclenchés dans le gestionnaire d'initiation de session d'appel et stoppés dans le gestionnaire de termi-naison d'appel.

La prise en compte des unités non-fonctionnelles a permis d'optimiser et de raner la compilation du DSL. Grâce à ce type de préoccupation et des outils adaptés, il est également possible d'enrichir le processus en introduisant par exemple du contrôle de ressources ou d'autres traitements sur les informations récoltées au niveau de la représentation abstraite. Ce type de démarche est très dicile à mettre en ÷uvre lors d'une compilation traditionnelle, car elle est intégrée à la génération de code et que les traitements sont disséminés dans le compilateur. Or, les objectifs de génération fonctionnelle d'un part, et l'optimisation ou l'enrichissement non-fonctionnel d'autre part, sont complètement diérents et pour être ecaces, ils doivent être appréhendés de manière distincte.