L'intérêt récent des architectes du cloud computing, essentiellement américains, pour les villes royales et historiques françaises est pour le moins singulier. La fondation Dojo, curatrice de la plateforme éponyme de bibliothèques de développement Javascript, proposait naguère le protocole de Bayeux pour les transmissions asynchrones de messages entre serveur et clients Web. Telle l'armure de la fameuse tapisserie, le protocole de Bayeux serait le bergame moderne de la narration de l'avènement du Cloud !
Bayeux
Bayeux propose un modèle publish and subscribe adapté aux protocoles de communication du Web (HTTP et dérivés). Ainsi un navigateur Web client commence par « s'abonner » à un ou plusieurs canaux de communication qui l'intéressent. Dans l'implémentation fournie par Dojo, le code Javascript suivant est exécuté par le navigateur au chargement de la page Web qui le contient :
<script type="text/javascript">
dojo.require("dojo.io.cometd");
cometd.init({}, "cometd");
cometd.subscribe("/hello/world", false, "publishHandler");
publishHandler = function(msg) {
alert(msg.data.test);
}
</script>
Les deux premières lignes du script chargent et initialisent la bibliothèque cometd
qui implémente le protocole de Bayeux dans la plateforme Dojo. La ligne suivante abonne la page au canal /hello/world
en déclarant la fonction à rappeler lorsqu'un message y circule, ici publishHandler
définie ensuite.
Le message, quant à lui, peut être envoyé à l'initiative du client ou à l'initiative du serveur. Depuis la page Web client, par exemple :
<input
type="button"
onclick="cometd.publish('/hello/world', { test: 'hello world' } )"
value="Click Me!">
Message
</input>
La commande publish
émet les données du second argument (au format JSON) sur le canal désigné par le premier argument.
Les messages peuvent également être émis depuis le serveur. Par exemple, dans une JSP le code suivant :
<%
Bayeux b = (Bayeux)getServletContext().getAttribute(Bayeux.DOJOX_COMETD_BAYEUX);
Channel c = b.getChannel("/hello/world",false);
Map<String,Object> message = new HashMap<String,Object>();
message.put("test", "Voici un message !");
c.publish( b.newClient("server_user",null),
message,
"new server message");
%>
Calais
Notre seconde étape du Tour de France des villégiatures du Cloud est Calais. OpenCalais pour être plus précis. Rien de plus naturel, penseriez-vous, après la tapisserie que de s'intéresser à la dentelle. Mais il est plutôt ici question de Web sémantique que des fuseaux et bobines des ourdisseurs, tullistes et autres wappeurs. OpenCalais crée automatiquement un graphe sémantique à partir du contenu, HTML, texte ou XML, qui lui est soumis. Le service OpenCalais en extrait les entités nommées, noms propres, noms de lieux, de sociétés, de livres etc. ainsi que les événements qui y sont mentionnés.
OpenCalais est de plus en plus utilisé par les fournisseurs de contenus et les éditeurs en ligne pour classer et catégoriser leurs publications. Ce service, tels les microformats, fait partie d'une nouvelle vague de produits et de services Web, comme ceux mis en ligne, par exemple, par Freebase, par Powerset acquis par Microsoft, par Evri acquéreur de Radar Networks/Twine, par Zemanta et par GetGlue qui tous proposent une alternative légère et pragmatique aux standards et protocoles du Web sémantique promus par le W3C — et fort énergiquement par Sir Tim Berners-Lee — considérés comme trop lourds à l'usage.
Le service OpenCalais offre des APIs complètes pour de nombreux langages de programmation mais peut tout aussi bien être mis en oeuvre via un simple formulaire HTML comme dans l'exemple suivant :
<form action="http://api.opencalais.com/enlighten/rest/"
method="post" accept-charset="utf-8">
licenseID: <input type="text" name="licenseID" />
<input type="submit" /><br />
content: <br />
<textarea rows="15" cols="80" name="content" ></textarea>
<br/>
paramsXML: <br />
<textarea rows="15" cols="80" name="paramsXML"/>
</textarea>
<br/>
</form>
Ce fragment HTML soumet le champ content
à l'analyse OpenCalais, après vérification de l'identité (licenseID
) du client du service.
Orléans
Si ce cheminement de traverse des belles provinces françaises donne à voir les monuments modernes du Cloud dans le temps même de leur élévation, c'est évidemment dans la ville royale d'Orléans que ces élans verront leur couronnement. C'est là, avec Orleans, que Microsoft Rex a un grain persistant. Et même plusieurs ! Des milliers...
Orleans est un framework de Microsoft Research pour construire des applications « client + cloud » qui simplifie la prise en charge de la concurrence des processus inhérente au cloud computing et de l'hétérogénéité des terminaux (du PC au smartphone) qui les utilisent.
Le modèle de programmation proposé par Orléans fragmente une application cloud en grains. Le grain est une unité de persistance des données, d'isolement au sens transactionnel, et de distribution sur un réseau de datacenters. Les grains communiquent entre eux par envoi asynchrone de messages — évoquant ici le protocole de Bayeux. Ces messages déclenchent alors des opérations transactionnelles chez d'autres grains. Plusieurs instances du même grain peuvent être simultanément actives pour traiter en parallèle des appels en nombre au même service. Les grains d'Orléans rappellent donc les objets CORBA de l'OMG de jadis — les transactions en plus et la mémoire partagée en moins. Le fameux « passage à l'échelle », qui rappelle immanquablement l'épreuve de l'échelle, torture médiévale qui fut sûrement déjà pratiquée dans la ville royale, est assuré par l'activation à la demande des grains.
Une des particularités intéressantes du modèle de programmation d'Orléans est la gestion de la communication asynchrone par l'intermédiaire de « promesses » qui sont ultérieurement tenues ou rompues. (On voit que l'on reste dans la solennité requise d'une visite de la cité royale !) C'est une idée qui remonte aux travaux de Barbara Liskov et Liuba Shrira (1988).
Les promesses d'Orléans, comme celle de la Pucelle de la même ville, sont de deux types : promesse d'une continuation ultérieure du calcul en cours ou promesse d'une valeur finale de ce calcul ultérieur, AsyncCompletion
et AsyncValue
respectivement. Ces promesses types sont intégrées à la plateforme .NET. Deux exemples pour illustrer :
// La promesse de calculer la valeur de A
AsyncValue<int> intPromise = GetA();
try{
// Attente synchrone (bloquante) que la promesse soit tenue
int A = intPromise.GetValue();
}
catch( Exception exc ){
// Relaps ! La promesse a été rompue.
Console.WriteLine( "Honte et apostasie. A ne sera pas connu :" +
exc.Message );
}
Cet exemple élémentaire montre la mise en oeuvre synchrone d'une promesse, ici celle de recevoir une valeur entière à un instant ultérieur. L'appel GetValue
est bloquant et attend la bonne fin du calcul de cette valeur. Avec une continuation, en revanche, on rend la communication complètement asynchrone :
// La promesse de calculer la valeur de A
AsyncValue<int> intPromise = GetA();
intPromise.ContinueWith(
(int A) => {
// Promesse tenue, on reçoit bien un entier
Console.WriteLine( "Résultat A = " + A.toString() );
},
(Exception exc) => {
// Promesse rompue ! Malheur et dévastation.
Console.WriteLine( "Erreur : " + exc.Message );
}
).Ignore();
Dans ce dernier cas, la promesse est associée à une continuation, c'est-à-dire une fonction exécutée lors de la notification ultérieure du résultat (un entier) ou de la rupture de la promesse. L'appel ContinueWith
n'est pas bloquant et son résultat est ici ignoré.
La classe d'un grain implémente une ou plusieurs de ses interfaces (qui dérivent de l'interface IGrain
). Toutes les méthodes et les propriétés d'une interface d'un grain sont soit de type AsyncCompletion
soit de type AsyncValue
, ce qui expose directement l'asynchronie des communications. En conséquence l'implémentation de ces méthodes doit renvoyer soit une valeur, qui sera convertie en promesse tenue par le runtime Orléans, soit une promesse obtenue de l'appel à un autre grain. Par exemple, une méthode d'un grain pour le calcul d'un produit de deux valeurs pourrait prendre les formes suivantes :
AsyncValue<int> Get_A_times_B(){
int x = this.A * this.B;
return x;
}
ou :
AsyncValue<int> Get_A_times_B(){
AsyncValue<int> p = grainVoisin.Get_A_times_B();
return p;
}
Le runtime d'Orléans se charge de l'initialisation, de la sauvegarde, de la réplication et de la migration des grains à l'exécution. Les politiques de persistance, d'initialisation, de réplication, etc. sont spécifiées par des annotations optionnelles ajoutées par le programmeur. Le runtime gère également la nature transactionnelle de l'exécution des méthodes granuleuses et la réconciliation des activations variées du même grain. (Joli petit problème de parcours de graphe élégamment résolu par les chercheurs de Microsoft.)
Après Bayeux et Calais, Orléans sera-t-elle la voie royale vers le cloud computing ? À l'époque de Jeanne d'Arc justement, s'apprêtait à régner le gentil dauphin Charles VII pour qui elle bouta les Anglais hors de France. Celui qu'on surnomma « le petit roi de Bourges » ne régnait plus que sur une partie de ce que fut le royaume. La populace le moquait alors en chantant le « carillon de Vendôme » sur l'air de l'angélus :
Mes amis,
Que reste-t-il
A ce dauphin si gentil ?
Orléans, Beaugency,
Notre-Dame de Cléry,
Vendôme, Vendôme !
Las ! Une roadmap technologique du XVème siècle ! Relevons enfin le défi du cloud computing français et, de crainte de voir l'envahisseur faire une percée d'Orléans à Vendôme, à nous de développer fièrement la plateforme cloud « Beaugency », les bibliothèques de programmation « collégiale Notre-Dame de Cléry », et l'infrastructure as a service « Vendôme » dans le style abbatial monumental !
Bonne et heureuse année de programmation cloud à tous les fidèles lecteurs d'ITR Manager.