I. Introduction

Cet article va vous apprendre à utiliser le WadRobotFramework (WRF) pour créer des robots destinés à Google Wave avec un minimum d'efforts.

Il n'a pas pour vocation d'expliquer l'utilisation de Google Wave.

WRF vous permettra d'écrire un robot simple en moins de cinq minutes.

II. Des robots pour Google Wave ?

Google Wave est un système de collaboration permettant une communication instantanée entre les participants. Ces participants pouvant être humains ou non.

Dans ce dernier cas, l'on nomme robots des programmes exécutés côté serveur, qui peuvent réagir à différents évènements d'une conversation.

Google fournit une API pour écrire des robots en Java (et en Python).

Un robot est un sous-ensemble d'une application Web, répondant à une URL établie.

Le mois de mars 2010 a vu arriver la v2 de l'API Java. Wave étant toujours un outil récent, son API n'est pas figée et susceptible de changements d'importance. Le WadRobotFramework est compatible avec cette nouvelle API. Les deux versions de l'API Robots de Google cohabiteront jusqu'au 30 juin 2010. Après cette date, seule la v2 sera utilisable en ligne.

III. Google Wave ?

Pour décrire Wave à l'emporte-pièce, disons que c'est un grand forum mondial qui possède des fonctionnalités proches de la messagerie instantanée et de la messagerie classique (e-mail). De ce fait, ce mélange novateur possède son propre vocabulaire.

La Wave, c'est le forum, chaque fil (thread) est nommé wavelet, et se compose de blips. Chaque wavelet possède un ou plusieurs participants, ce sont soit des humains soit des robots.

Incroyablement novateur non ? A première vue, non, mais notons pour ultérieurement la possibilité d'ajouter des gadgets dans une conversation, ce qui ouvre un large panorama de possibilités.

IV. Pré-requis

Les pré requis pour pouvoir utiliser le WRF sont les mêmes que ceux pour l'API de Google.

  • Avoir accès à Google Wave (Depuis la conférence Google IO, GW est ouvert à tous sur inscription)
  • Avoir un compte développeur sur App Engine Java
  • Pouvoir y créer une application
  • Disposer d'Eclipse et du plugin Google
  • Télécharger l'API Google

Lors de Google I/O 2010, outre l'ouverture à tous et l'intégration à l'offre Google Apps Entreprise, il a été annoncé que désormais, les robots pour GW pourraient être hébergés en dehors de Google App Engine (GAE). Dans cet article, ce ne sera pas le cas.

V. Robots - la méthode Google

La méthode pour écrire des robots est extrêmement bien décrite dans le tutoriel publié à cette adresse
http://code.google.com/intl/fr-FR/apis/wave/extensions/robots/java-tutorial.html

V-A. Exemple de code standard

Ci-dessous le code d'un robot minimal possédant deux fonctions:

  • dire qu'il est vivant (I'm alive) lorsqu'il est ajouté à une conversation.
  • saluer tous les participants (Hi, everybody!)lorsqu'un participant est ajouté
java
Sélectionnez

package parroty;

import com.google.wave.api.*;
import com.google.wave.api.event.*;

public class ParrotyServlet extends AbstractRobot {

  @Override
  protected String getRobotName() {
    return "Parroty";
  }

  @Override
  protected String getRobotAvatarUrl() {
    return "http://code.google.com/apis/wave/extensions/robots/images/robot_avatar.png";
  }

  @Override
  protected String getRobotProfilePageUrl() {
    return "http://code.google.com/apis/wave/extensions/robots/java-tutorial.html";
  }

  @Override
  public void onWaveletSelfAdded(WaveletSelfAddedEvent event) {
    Blip blip = event.getWavelet().reply("\nHi everybody!");
  }

  @Override
  public void onWaveletParticipantsChanged(WaveletParticipantsChangedEvent event) {
    for (String newParticipant: event.getParticipantsAdded()) {
      Blip blip = event.getWavelet().reply("\nHi : " + newParticipant);
    }
  }
}

Rien de très compliqué en apparence. En partie parce que cela s'est grandement simplifié par rapport à la v1 de l'API.

Ce code n'est pas des plus excitant pour vos neurones, mais... il y a encore moins excitant.

Pour que ce code soit exécuté lorsque vous ajoutez un robot à une conversation, il faudra au préalable :

  • avoir un environnement de programmation prêt
  • récupérer le Jar de l'API des robots et ses dépendances (Json)
  • déclarer la servlet avec son path spécifiques à respecter (web.xml)
  • écrire le fichier de déploiement (appengine-web.xml)
  • écrire le code "métier"
  • configurer le projet sous Eclipse (classpath)

Sachez qu'avec la v1, il y avait plusieurs étapes supplémentaires.
Bien entendu, du copier-coller à partir des tutoriels fait l'affaire techniquement, mais cela apporte une faible satisfaction.

De plus, c'est à répéter pour chaque nouveau robot.

Heureusement, le WadRobotFramework est là !
Voici un exemple de code WRF

java
Sélectionnez

import org.wadael.waverobotfrmwrk.simple.BlipModifierRobot;
/**
 * Example robot that adds RTFM!! after each question mark.
 * It assumes there is a manual for the conversation's themes.
 * 
 * @author jerome baton : Wadael, http://blog.wadael.org
 */
@SuppressWarnings("serial")
public class RTFMRobotServlet extends BlipModifierRobot {
    @Override
    protected String modifyBlipText(String actualText)  {
        if(actualText.indexOf("?") == -1) return null;
        else {
           return actualText.replaceAll("?", "? (RTFM!!") ;
             }
        }
}

VI. WadRobotFramework

VI-A. Principe

Le WRF est destiné à des programmeurs, il se présente sous la forme d'un projet pour Eclipse.

Ce projet contient les deux composantes du WRF :

  • le générateur
  • l'API

Chaque composant est lié à une étape du projet et rend plus rapide son déroulement.

Le générateur rend plus rapide la création du robot et l'API rend plus rapide l'écriture.

VI-B. Historique

Ce projet a suivi un développement incrémental depuis décembre 2009

Au début, fût l'API, elle permit de moins coder, puis vint le projet exemple qui permit de ne plus avoir à recréer tous les fichiers de configuration, puis l'API fût complétée par les robots avancés et enfin, arriva le générateur.

VI-C. API spécifique

L'API du WRF est une surcouche de l'API fournie par Google, elle définit un ensemble de classes notamment celles correspondant aux différents types de robots proposés par le WRF.

Elle s'utilise par simple héritage comme nous le verrons ultérieurement.

VI-D. Générateur

Le générateur est constitué d'un script Ant secondaire et de son fichier de configuration.

Il s'utilise à partir du script Ant principal (build.xml), où l'on choisit la cible (target) Ant à exécuter, correspondante au type de robot voulu.

Quelques secondes plus tard, vous disposerez d'un squelette de robot où seule la logique métier restera à implémenter.

VII. Utilisation du générateur

Pour utiliser le générateur, il est préférable de d'abord le configurer.

VII-A. Configuration du générateur

La configuration du générateur se fait en deux étapes. La première, que j'appelle "configuration générale" doit être réalisée une seule fois par station.

Quant à la "configuration pour un robot", elle est à faire pour chaque nouveau robot.

La durée cumulée de ces deux étapes est inférieure à deux minutes.

VII-A-1. Configuration générale

J'ai fait le choix qu'à chaque génération de robot, la librairie est compilée et son archive recréée. Cela m'a permis d'être certain que les robots successivement créés dans le cadre du développement de WRF l'étaient bien avec la dernière version.

La dépendance vers l'API de Google implique que cette dernière doit être dans le CLASSPATH utilisé par Ant lors de la compilation.

Il vous faut donc renseigner le fichier build.properties situé à la racine du projet pour que la clef plugin.lib.dir ait pour valeur le chemin du répertoire du plugin Eclipse où se trouvent les JAR de Google App Engine (exemple de JAR: appengine-local-runtime-shared.jar).

Exemple de chemin : c://tools//IDEs//eclipse35//plugins//com.google.appengine.eclipse.sdkbundle_1.2.6.v200910131704//appengine-java-sdk-1.2.6//lib//shared

Vient ensuite une configuration pour chaque robot que vous souhaitez créer.

VII-A-2. Configuration pour un robot

La personnalisation de la création d'un robot se fait également par l'utilisation d'un fichier de propriétés Java standard. Celui-ci a pour chemin generator/generator.properties, à partir de la racine du projet.

La configuration indique :

  • le package à utiliser
  • le nom du robot
  • son numéro de version
  • le nom de l'application de déploiement
  • le domaine de l'application de déploiement

Des explications (en anglais) sont intégrées dans le fichier lui-même, mais comme le fichier proposé est déjà valorisé, il vous suffit de modifier les valeurs existantes par des valeurs 'correctes' correspondant à ce que vous souhaitez.

Après l'exécution, la configuration pour un robot est ensuite sauvegardée à la racine du répertoire dédié au robot généré.

VII-B. Exécuter le générateur

Dans le fichier build.xml à la racine du projet WRF, vous trouverez trois " target " Ant qui sont :

  • generate_SimpleAppenderRobot
  • generate_SimpleModifierRobot
  • generate_AdvancedRobot

Exécutez celle qui correspond le mieux au robot que vous souhaitez créer.

Les différents types de robots sont expliqués ci-après.

VIII. Les types de robots

WRF définit plusieurs types de robots. A ce jour, il existe trois types de robots dont deux types simples et un type avancé.

VIII-A. Robots simples (RS)

Les robots simples réagissent à chaque blip ajouté à une conversation. Ils sont limités à du texte simple, sans mise en style.

VIII-A-1. Modifieurs-BlipModifierRobot

Un robot "modifieur" n'aura comme possibilités que

  • modifier le blip
  • ne pas modifier le blip

Dans le code source de votre robot, héritant de BlipModifierRobot, il vous faudra implémenter la méthode abstraite :

java
Sélectionnez
protected abstract String modifyBlipText(String actualText) ;

Si votre implémentation renvoie une chaîne non nulle, alors le blip sera modifié, avec pour contenu la chaine renvoyée par votre implémentation et votre robot sera ajouté comme auteur supplémentaire du blip.

Si votre robot renvoie null alors le blip restera inchangé sur les deux points.

VIII-A-2. Ajouteur-BlipAppenderRobot

Un robot "ajouteur" n'aura comme possibilités que

  • ajouter un blip après le blip reçu
  • ne pas ajouter de nouveau blip à la conversation

Dans le code source de votre robot, héritant de BlipAppenderRobot, il vous faudra implémenter la méthode abstraite :

java
Sélectionnez
protected abstract String getTextToAppend(String textOfTheBlipToReactFrom);

Si votre implémentation renvoie une chaîne non nulle, alors un nouveau blip sera créé, avec votre robot pour auteur.

Si votre robot renvoie null, alors la conversation restera inchangée (ni nouveau blip, ni le robot en tant que participant à la conversation).

VIII-B. Robots avancés (RA)

VIII-B-1. Définition d'un RA

Un RA est à voir comme une chaîne de production tayloriste basée sur la division du travail, car sa nature est d'être composé de plusieurs Workers chainés, qui réagissent chacun à une commande (ou non) mais peuvent aussi interrompre la chaine du traitement.

Un RA possède un identifiant (méthode getRobotIdentifier à surcharger) dont l'utilité est de permettre l'utilisation de plusieurs RA au sein d'une même conversation.

VIII-B-2. Définition d'un Worker

Un worker correspond à une tâche, une unité de travail. On les programmera à priori, de façon à ce qu'ils soient sans état. Dans l'implémentation, cela correspond à l'interface RobotWorker

Voici le code source de cette interface

java
Sélectionnez

public interface RobotWorker {
    /**
     * Returns a string identifying an instruction delimiting the scope of this robot.
     * Can be null, so that the worker is executed whatever the instruction. 
     */
    public String getInstruction();
    
    /**
     * Returns a description of the instruction's behaviour.
     * This description is used when the robot's usage is displayed. 
     * @return
     */
    public String getDescription();
    
    /**
     *  Entry-point for a worker.
     * You get all the objects you can use.
     * 
     * @param bundle
     * @param blip
     * @param event
     * @param parameters may be null
     * @return
     * 
     */
    public boolean doWork(RobotMessageBundle bundle, Blip blip, Event event, String parameters);
}
....

On y lit qu'une implémentation de worker doit définir les méthodes

  • getInstruction
  • getDescription et,
  • doWork

Les noms sont assez explicites.
Il faut savoir que getInstruction et getDescription sont utilisées dans le cas où l'utilisateur demande de l'aide en créant un blip débutant par /help.

Quant à doWork, c'est dans cette méthode que vous définirez la logique du worker. En paramètres, vous disposez de tous les objets mis à disposition par l'API Google.

VIII-B-2-a. Worker sans papier (WSP)

Un WSP est un worker dont l'instruction est délibérément null c'est à dire que getInstruction() renvoie null.
Dans ce cas, le WSP sera exécuté pour chaque blip de la conversation à laquelle participe le RA et le WSP n'apparaitra pas dans les instructions déclarées par le RA en réaction à la demande d'aide de l'utilisateur.

VIII-B-3. Relation RA-Worker

Un RA peut posséder plusieurs workers, chacun pouvant être utilisé au sein de plusieurs RA. D'où l'attention à porter à ce qu'il soit sans état par défaut.

Les RA montrent leurs RobotWorkerlorsqu'un blip commence par /help

VIII-B-4. Différence avec les robots simples

Les RA diffèrent des RS sur deux points essentiels.

Le premier point est l'accès aux mêmes objets que l'API proposée par Google. Les RS les masquent pour une raison de simplicité

Le deuxième est la différence d'utilisation. Les RS ont des possibilités bien plus réduites que les RA.

VIII-B-5. Exemple de RA

Je vais reprendre ici une francisation de l'exemple que j'ai mis sur le wiki du projet. Sa valeur est uniquement pédagogique.

java
Sélectionnez

 package org.wadael.generated.advRobot.advAppender; 

import org.wadael.waverobotfrmwrk.advanced.RobotWorker; 
import org.wadael.waverobotfrmwrk.advanced.WithWorkersRobot; 
 
import com.google.wave.api.Blip; 
import com.google.wave.api.Event; 
import com.google.wave.api.RobotMessageBundle; 
/** 
 * AdvAppenderExample 
 * 
 * @author generated by the WadRobotFramework 
 * 
 */ 
@SuppressWarnings("serial") 
public class ExampleAjouteurAvanceServlet extends WithWorkersRobot { 

    public ExampleAjouteurAvanceServlet(){ 
        super(); 
        /* On ajoute ici le ou les workers */ 
        addRobotWorker( new LengthWorker() ); 
        addRobotWorker( new CapitalWorker() ); 
    } 
     
    @Override 
    public String getRobotIdentifier() { 
        return "RA"; 
        /* un identifiant identifie un RA dans une conversation, car il peut y en avoir plusieurs. 
        ASTUCE : FAIRE COURT ! 
        */ 
    } 

    @Override 
    protected String getRobotSelfIntroduction() { 
        /* TODO Renvoyer le texte retourné par le robot quand il est ajouté à une conversation */ 
        return "Salutations."; 
    } 
     
    @Override 
    protected String getDisplayName() { 
        return "Robot avancé d'exemple pour Developpez.com"; 
    } 
} 


/*  
    Premier worker 
*/ 
public class LengthWorker implements RobotWorker { 
    @Override 
    public String getInstruction() { 
        return "taille"; 
    } 

    @Override 
    public String getDescription() { 
        return "Affiche la taille du blip."; 
    } 

    @Override 
    public boolean doWork(RobotMessageBundle bun, Blip bli, Event eve,String params) 
    {     
        Blip lengthChild = bli.createChild(); 
        lengthChild.getDocument().append("taille : " + bli.getDocument().getText().length() + " caractères"); 
        return true; 
    } 
} 

/*  
    Deuxieme worker 
*/ 
public class CapitalWorker implements RobotWorker { 
    @Override 
    public String getInstruction() { 
        return "capi"; 
    } 

    @Override 
    public String getDescription() { 
        return "Capitalise le texte du blip"; 
    } 

    @Override 
    public boolean doWork(RobotMessageBundle bun, Blip bli, Event eve,String params) 
    {     
        Blip lengthChild = bli.createChild(); 
        String capiTexte = bli.getDocument().getText().toUpperCase(); 
        lengthChild.getDocument().replace(capiTexte); 
        return true; 
    } 
} 

Les Worker doivent être définis dans leur propre fichier

VIII-B-6. Utilisation des RA

Là où les RS ont un comportement automatisé, les RA réagissent surtout à des commandes insérées par l'utilisateur au sein d'un blip. L'objectif principal de ce type de robot est qu'un même RA puisse réagir à plusieurs commandes différentes.

Les RA seront codés de telle manière que leur utilisation soit expliquée lorsqu'ils se présentent, en pointant vers un site web par exemple.

Les RA sont riches, riches de commandes.

Ils ont leurs commandes officielles (1 commande utilisateur = 1 worker implémenté). Ce sont celles qui sont listées lorsqu'un utilisateur valide un blip commençant par /help (valeur par défaut, reconfigurable).

Ils peuvent aussi avoir des commandes officieuses, de l'ombre. Elles correspondent aux workers faisant partie d'un RA mais retournant null comme instruction (méthode getInstruction() ).

Ils ont aussi des commandes standard, avec "/help" actuellement seule de cette catégorie mais qui sait ...

VIII-B-7. Les différents types de RA

Une sous-classe de RA a été créée afin d'obéir à la wavetiquette.

Un autre type de RA est en préparation.

IX. Utilisation : pas à pas

Pour continuer ce tutoriel, il est temps d'abandonner la théorie pour passer à la pratique et créer un robot via le générateur.

Le point de départ est que tous les pré-requis sont satisfaits. Sous Eclipse, vous avez donc un project WadRobotFramework ouvert, créé à partir d'une archive ZIP récupérée sur le site.

1/ Adapter le fichier build.properties

2/ Configurer le générateur pour un résultat personnalisé, en adaptant le fichier generator/generator.properties

3/ Choisir un type de robot

4/ Lancer la tache Ant voulue (revoir le paragraphe 7)

Après ces quatre premières étapes, vous verrez dans la console d'Eclipse un message vous indiquant où trouver le squelette de robot généré.

Votre écran ressemble à la capture ci-dessous.

Image non disponible

Le projet du robot que vous venez de créer se trouve dans generated_Robots. Il faut maintenant créer un nouveau projet pour votre robot afin qu'il soit pris en compte dans votre workspace.

Si votre Eclipse est en anglais, faites un clic droit dans la partie " Package Explorer " (à gauche) et choisissez " Import ". Puis " Existing project into workspace ", comme sur la capture ci-dessous.

Image non disponible

Choisissez en " root directory " la racine du répertoire de votre robot fraichement généré.

Image non disponible

L'astuce est de cocher la case "Copy projects into workspace". Cela permet de dupliquer l'arborescence (qui est générée dans $WRF_HOME$/generated_robots) à l'endroit voulu du workspace.

Image non disponible

Ci-dessus, choix du répertoire "racine" du robot généré.

Image non disponible

Dans cet exemple, mon robot était nommé "dev" comme on peut le voir dans la zone "Projects".

En cliquant sur "Finish", vous avez désormais votre projet de robot prêt à être terminé puis déployé. Le déployement se fait comme pour les autres applications web à la Google, à savoir qu'il est initié par le bouton à l'icone d'avion.

J'ai réalisé une vidéo de l'utilisation du générateur, vous la trouverez à l'adresse suivante :

X. La suite

Que va-t'il se passer pour le WRF dans l'avenir ?

Pour répondre à cette question, le wiki possede une page WhatsNext sur laquelle j'essaie de centraliser les différents points qui seront traités ultérieurement, qu'ils soient des ajouts ou des modifications.

De nouvelles fonctionnalités seront ajoutées, parmi lesquelles :

  • ne répondre qu'à une liste limitée d'utilisateurs (mise en place souscription)
  • les commandes d'administration correspondantes
  • générer des bots XMPP (utilisables dans Google Chat) et des robots ajouteurs en même temps (avec le même code métier) via un nouveau type de robot.
  • Effacer les commandes (ou non) des blips
  • Éventuellement, intégrer de nouveaux développeurs sur le projet.
  • la création d'un nouveau type de robot (schizophrène)

XI. Conseils

Inscrivez-vous au groupe pour avoir des informations fraîches et/ou poser des questions.

Utilisez SVN plutôt que les distributions car une fois que vous aurez créé un projet WadRobotFramework dans votre workspace, il sera si simple de mettre WRF à jour.

XII. Liens

Le framework : http://code.google.com/p/wadrobotframework

Tutoriels en anglais, par Romin Irani :

Je pense devoir préciser que Romin est un ami, mais cela ne change en rien la qualité de ses tutoriaux. Il a publié un PDF regroupant l'ensemble des tutoriels (en anglais) qu'il a écrit sur Google App Engine et ses APIs.
Ce PDF est disponible à l'adresse suivante :
http://gaejexperiments.wordpress.com/gaej-experiments-ebook/

Liste des articles sur la programmation Wave :
http://code.google.com/intl/fr/apis/wave/articles.html

Ma présentation sur la v1 de WRF (partiellement périmée):

Mon site : http://www.wadael.org

Mon Twitter : http://twitter.com/wadael

A vos commentaires sur le forum 3 commentaires Donner une note à l'article (4.5)

XIII. Remerciements

Je remercie chaleureusement Wachter d'avoir effectué la relecture de cet article, ainsi que l'équipe de la rédaction de Developpez.com, Eric Siber, Caro-Line, Ricky81 et Hornetbzz pour leur accueil et leur aide.