DOJO et le protocole de Bayeux. DOJO est l'initiateur du protocole de Bayeux - j'avoue ne pas avoir trouver de relation avec la ville de Bayeux et ces tapisseries, en même temps il n'y a certainement aucune relation...Bref, Dojo propose une API cliente JavaScript permettant d'interagir avec un serveur implémentant ce fameux protocole de Bayeux. Glassfish - via Grizzly - étant un des serveurs implémentant ce protocole, il est tout à fait possible d'imaginer un client utilisant DOJO et s'interfaçant avec Glassfish.
Certaines solutions de développement - a contrario des solutions portées par le serveur d'application ou le conteneur de servlet présentés précédemment - intègrent cette problématique :
Le protocole de Bayeux, poussé par DOJO, vise une normalisation permettant de délivrer des évènements, au format JSON, entre des clients et un serveur, des clients et des clients (via le serveur..), sur la base du modèle publish/subscribe.
Ce protocole repose " principalement " sur :
Ainsi dans ce protocole, un exemple de message est :
/*[{"channel":"/cometd/myChannel","successful":true,"clientId":"2d714396f339f90d","id":"6"},
{"channel":"/cometd/myChannel","data":{"test":"one
message"},"id":"6","clientId":"2d714396f339f90d"}]*/
Ce protocole ne définit pas d'API cliente ou serveur mais décrit seulement les mécanismes d'échanges entre serveur et clients dans le cadre d'échange de type " push ".
Loin de moi l'envie de vous refaire un tutorial complet sur Grizzly. Reste que ces APIs sont assez simples et proposent les principaux concepts suivants :
En terme de code, les APIs sont utilisées dans une servlet comme suit :
public void init(ServletConfig config) throws ServletException {...
CometEngine engine = CometEngine.getEngine();
CometContext cometContext = engine.register(contextPath);
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
SampleCometHandler handler = new SampleCometHandler();
handler.attach(resp);
CometContext context = CometEngine.getEngine().getCometContext(contextPath);
context.addCometHandler(handler);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
CometEngine engine = CometEngine.getEngine();
CometContext context = engine.getCometContext(contextPath);
context.notify(req.getParameter("company"));
...
private class SampleCometHandler implements CometHandler {
public void onEvent(com.sun.grizzly.comet.CometEvent event) throws IOException {
if (event.getType() != CometEvent.NOTIFY) {
// le client a fait le post
this.response.getWriter().write("message: " + event.attachment());
this.response.getWriter().flush();
// supprimer cette ligne pour faire du streaming
event.getCometContext().resumeCometHandler(this);
}
}
Reste maintenant à implémenter un " petit " client, simplement en JavaScript et de la manière suivante :
function doGet(){
new Ajax.Request('/CometSample/CometSampleServlet', {
method:'get',
onSuccess: function(transport){
$('result').update(transport.responseText);
}
});
}
function doPost(){
new Ajax.Request('/CometSample/CometSampleServlet', {
method:'post',
parameters: {company:'octo' },
onSuccess: function(transport){...}
});
}
Grizzly fournit une implémentation du protocole de Bayeux via une servlet " générique " qu'il est simplement nécessaire de configurer au niveau du fichier web.xml
<servlet>
</servlet><servlet -name>Grizzly Cometd Servlet</servlet>
<servlet -class>com.sun.grizzly.cometd.servlet.CometdServlet</servlet>
<init -param>
<param -name>expirationDelay</param>
<param -value>60000</param>
</init>
<load -on-startup>1</load>
<servlet -mapping>
</servlet><servlet -name>Grizzly Cometd Servlet</servlet>
<url -pattern>/cometd/*</url>
Côté client, le framework DOJO fournit une extension JavaScript permettant de s'abonner à un channel et de publier des messages.
<script type="text/javascript">
dojo.require("dojox.cometd");
dojox.cometd.init("http://localhost:8080/CometSample/cometd" );
dojox.cometd.subscribe("/cometd/myChannel", function(msg)
{
$('result').update('message received : ' + msg.data.test);
});
</script>
<ul>
<li>Concernant la publication</li>
</ul>
var data = $F('text2Send');
dojox.cometd.publish('/cometd/myChannel',{test: data });
La principale limitation à la mise en oeuvre de Comet vient en fait des browsers. Ces derniers ne permettent en général de n'ouvrir que deux connexions http par domaine. En fait, c'est même conseillé dans la norme HTTP/1.1. Cet article de 2006 donne pas mal de détail sur cette limitation. J'ai pu tester cette limitation (sur Firefox 3.0.1) sur mes exemples : lorsque deux de mes browsers ouvraient des connexions de type GET sur le domaine localhost :8080, la seconde connexion GET était systématiquement mise en attente...en remplaçant simplement localhost par mon IP (et donc en changeant de domaine), le problème se résout. Au-delà de l'anecdote, cette limite de deux connexions pose un problème avec le long-polling qui monopolise une des deux connections mais il y a fort à parier que les constructeurs vont résoudre le problème, IE8 devrait déjà porter le nombre de connections à 8...
L'API Grizzly me parait très naturelle à utiliser et masque vraiment les problématiques de manipulation de thread ; elle gagnerait à fournir une petite librairie JavaScript permettant d'automatiser l'ouverture de la connexion ainsi que la reprise en cas de timeout... On peut de plus regretter la forte imbrication Grizzly/Glassfish : il semble délicat - pour avoir essayé, rapidement certes... - d'imaginer utiliser le moteur http Grizzly dans Tomcat... A l'inverse, DOJO fournit un client JavaScript bien pensé - au travers de son extension dojox.cometd - et l'implémentation du protocole de Bayeux par Grizzly a cela de génial qu'elle ne demande - pour les cas nominaux d'utilisation - pas de développement supplémentaire : juste la configuration d'une servlet. Reste que ces solutions sont encore artisanales - au sens étymologique, donc positif. Les APIs aussi bien côté serveur que client ne sont pas encore définies mais il faut noter que les mécanismes de " push server " seront standardisés dans la version 3.0 de Servlet - donc les containeurs de servlet JEE6 -. Reste enfin que les cas d'application dans l'informatique d'entreprise ne sont pas forcément des plus répandus et aujourd'hui plutôt implémentés par des solutions RDA, mais demain qui sait ? ;-)