insideIT.fr : le blog des architectes IT de SFEIR

Aller au contenu | Aller au menu | Aller à la recherche

Tag - google web toolkit

Fil des billets - Fil des commentaires

jeudi 10 février 2011

Retour d'expérience d'un projet GWT : 5 Implémentation Modèle-Vue-Présenteur (5/8)

Le contexte:

Le projet a pour but d'améliorer l'ergonomie et l'usabilité du back office d’un produit en cours de développement réalisé en collaboration avec SFEIR

Dans le cadre de ce projet, la version de GWT utilisée passe de la 1.7.1 à la 2.0.3 afin de bénéficier des nouvelles fonctionnalités offertes par cette version. De nouveaux pattern de développement ont également été mis en place au cours de ce projet.

Voici une série d'article sur les nouveautés de GWT 2, les choix d'architectures, et bibliothèques utilisés qui font part de notre retour d'expérience sur le sujet. Ces articles ont été écris par David Aboulkheir, Patrice de Saint Steban et Cyril Lakech

  1. Nouveautés de GWT 2.0
  2. UiBinder, enfin une forte collaboration entre le designer et le développeur
  3. Intégration facile de maquette Html en GWT 2
  4. Architecture Modèle-Vue-Presenteur
  5. Implémentation Modèle-Vue-Présenteur
  6. Ecrire des tests unitaires avec Mockito
  7. Mise en place de Gin sur le projet
  8. Internationalisation

Voyons maintenant comment créer une architecture Model-View-Presenter.

Le présenteur doit étendre la classe Presenter qui fournit des fonctionnalités de base à notre application. Comme l'accès au global event bus et à la factory de vue.

public class TestPresenter extends Presenter {

    /**
     * Interface represents the test view
     */
    public interface Display extends DisplayView {
        public void setUserName(String username);

        public HasClickHandlers getUserNameClickHandler();
    }
   
    // fields
    /** View */
    Display display;
   
    // constructor
    public TestPresenter(Display display, HandlerManager globalEventBus, DisplayFactory factory) {
        super(globalEventBus, factory);
        this.display = display;
       
        bind();
    }
   
    // Bind all event
    private void bind(){
                getGlobalEventBus().addHandler(
            OnUserLoggedEvent.getType(),
            new  OnUserLoggedEvent.Handler() {
            @Override
            public void onUserLogged(OnUserLoggedEvent event) {
                display.setUserName(event.getUser()
                        .getLogin());
            }
        });
        display.getUserNameClickHandler().addClickHandler(
            new ClickHandler() {
                public void onClick(ClickEvent event) {
                    getGlobalEventBus().fireEvent(
                        new OnUserLogout());
            }
        }       
    }

    public void go(Placer panel) {
        panel.setView(display);
    }
}

Nous avons ici l'architecture de base d'un presenter :

  • Le constructeur prend en paramètre toutes les interfaces qu'il va utiliser :
    • sa vue interfacé par l'interface interne au presenter : Display
    • le global event bus (Bus d'évènement global à l'application pour la communication entre les presenter)
    • la factory de vue (utilisée pour instancier les vues des sous-presenters)
    • Éventuellement des services RPC
  • la méthode bind() qui s'occupe d'enregistrer le présenteur aux évènements globaux de l'application (ici le login de l'utilisateur) et aux évènements de la vue (ici le click sur le label affichant le login de l'utilisateur).
  • la méthode go(), qui permet au présenteur de s'afficher
    • la classe Placer est une abstraction d'un Panel GWT, pour être complètement indépendant de GWT, cette interface possède une simple méthode setView qui prend en paramètre un DisplayView. L'interface DisplayView qui doit être étendu par toutes les vues demande juste d'implémenter la méthode asWidget() qui permet de retourner la vue (this) en tant que Widget GWT.

Créons maintenant la vue, en utilisant UiBinder :

public class TestView extends Composite implements TestPresenter.Display {

    private static TestViewUiBinder uiBinder = GWT
            .create(TestViewUiBinder.class);

    interface TestViewUiBinder extends
        UiBinder<Widget, TestView> {}

    @UiField Label label;
   
    public TestView() {
        initWidget(uiBinder.createAndBindUi(this));
    }

    @Override
    public HasClickHandlers getUserNameClickHandler() {
        return label;
    }

    @Override
    public void setUserName(String username) {
        label.setText(username);
    }

    @Override
    public Widget asWidget() {
        return this;
    }
}

Avec le fichier TestView.ui.xml associé :

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    xmlns:g="urn:import:com.google.gwt.user.client.ui">
    <g:Label ui:field="label" />
</ui:UiBinder>

Cette classe étend donc notre Display du présenteur et accède aux composant GWT.

On peux ainsi tester facilement le code de notre présenteur car il ne possède aucune adhérence à GWT.

Nous avons choisi dans un premier temps de se passer de ces framework et d’appliquer les pattern MVP en suivant uniquement les pratiques conseillées par Google. Maintenant que nous avons une première expérience avec le développement MVP, nous pouvons penser à utiliser un de ces framework pour bénéficier de leurs utilitaires comme la gestion de l’historique, du pattern action etc. Si nous devions en choisir un à ce jour, ce serait gwt-platform qui est issu de gwt-presenter et gwt-dispatch.

lundi 3 janvier 2011

Retour d'expérience d'un projet GWT : 3 Intégration facile de maquette Html en GWT 2 (3/8)

Le contexte:

Le projet a pour but d'améliorer l'ergonomie et l'usabilité du back office d’un produit en cours de développement réalisé en collaboration avec SFEIR

Dans le cadre de ce projet, la version de GWT utilisée passe de la 1.7.1 à la 2.0.3 afin de bénéficier des nouvelles fonctionnalités offertes par cette version. De nouveaux pattern de développement ont également été mis en place au cours de ce projet.

Voici une série d'article sur les nouveautés de GWT 2, les choix d'architectures, et bibliothèques utilisés qui font part de notre retour d'expérience sur le sujet. Ces articles ont été écris par David Aboulkheir, Patrice de Saint Steban et Cyril Lakech

  1. Nouveautés de GWT 2.0
  2. UiBinder, enfin une forte collaboration entre le designer et le développeur
  3. Intégration facile de maquette Html en GWT 2
  4. Architecture Modèle-Vue-Presenteur
  5. Implémentation Modèle-Vue-Présenteur
  6. Ecrire des tests unitaires avec Mockito
  7. Mise en place de Gin sur le projet
  8. Internationalisation

Exemple d'intégration d'un composant d'une page Web dans un projet GWT 2:

Nous devons intégrer un nouveau composant qui nous est livré sous la forme de maquette HTML qui se compose de fichiers HTML, d'image et éventuellement de fichier CSS.

Voici le fichier HTML fourni, il contient le code HTML et le style CSS utilisé:

<style>
<!--

* {
    font-family:calibri;
    font-size:12px;
}

.menu {
    padding: 0px;
    background: url('bgmenu.gif') repeat-y right top white;
    display:block;
    color:#1783c4;
    width:250px;
    height:100%;
}

.menu h2{
    font-family:calibri;
    font-size:18px;
    background: url('menutop.gif') no-repeat bottom left;
    width:250px;
    padding-bottom:10px;
    margin:0px;
}

.menu .close{
    float:right;
    margin:4px;
    margin-right:7px;
}

.menu textarea {
    width:240px;
    min-height:300px;
    border:1px solid #dddddd;
    background: #f6f6f6;
    margin-top:20px;
    margin-bottom:5px;
}

.pages{
    padding:3px 7px 7px 7px;
}

.pages.selected{
     background: url('menubottom.gif') no-repeat bottom left #f5f5f5;
}

.pages .close{
    float:right;
}

.pages a.element{
    color:black;
    font-size:13px;
    font-weight:bold;
    margin-bottom:3px;
    text-decoration:none;
    display:block;
}

.pages a.element:hover{
    text-decoration:underline;
    background:url('croixnoire.gif') 223px 3px no-repeat;
}

.pages .close{
    float:right;
    width:13px;
    height:11px;
}

.right {float:right;}

a.bouton {
    color:white;
    font-size:12px;
    font-weight:bold;
    text-transform:uppercase;
    margin-right:10px;
    padding:2px 5px;
    text-decoration:none;
    font-family:calibri;
    border:1px solid #909090;
    text-align:center;
}

a.bouton.bleu {
    background:#0099cb;
}

a.bouton.bleu:hover {
    background:#0fb3e9;
}

a.bouton.vert {
    background:#4ba600;
}

a.bouton.vert:hover {
    background:#5cc803;
}
-->
</style>
<div class="menu">
      <div class="close"><a href="#"><img src="croix.gif" border="0"></a></div>
     <h2>Jean-Pierre Dupont</h2>   
     <div class="pages selected">
       <a href="#" class="element"><img src="1ptrans.gif" border="0" class="close">Ma page personnel (0)</a>
      </div>
     <div class="pages">
        <a href="#" class="element"><img src="1ptrans.gif" border="0" class="close">Autre page (0)</a>
     </div>
    <br/>
     <a href="#" class="bouton bleu">Créer une nouvelle page</a>
     <textarea>
     Ici je peux mettre des notes
     </textarea>
     <a href="#" class="bouton vert right">Enregistrement</a>
</div>

Nous créons un nouvel élément UiBinder que nous appelons HomePageMenu :

UIBinder create

On modifie le fichier HomePageMenu.gwt.xml comme suit:

  • On ajoute les entêtes nécessaires pour UiBinder
  • On modifie la balise <style /> en <ui:style />
  • On remplace la div principale par une balise <g:HTMLPanel />
  • Les libellés que l’on souhaite rendre dynamiques sont remplacés par des balises <g:InlineLabel />, les liens <a /> par des <g:Anchor /> et les <textarea /> par des <g:TextArea />
  • Les nom des styles utilisés sont modifiés, en lieu et place de “monStyle” on utilise "{style.monStyle}"
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
     xmlns:g="urn:import:com.google.gwt.user.client.ui">
     <ui:style>
        * {
            font-family: calibri;
               font-size: 12px;
        }
       
        .menu {
               padding: 0px;
            display: block;
             color: #1783c4;
            width: 250px;
            height: 100%;
        }
       
        .menu h2 {
            font-family: calibri;
            font-size: 18px;
            background: url('module/images/homepage/menutop.gif')
                 no-repeat bottom left;
            width: 250px;
             padding-bottom: 10px;
            margin: 0px;
        }
      
        .menu .close {
            float: right;
             margin: 4px;
            margin-right: 7px;
        }
        
        .menu textarea {
            width: 240px;
                min-height: 300px;
            border: 1px solid #dddddd;
               background: #f6f6f6;
            margin-top: 20px;
             margin-bottom: 5px;
        }
       
        .pages {
               padding: 3px 7px 7px 7px;
        }
       
         .pages.selected {
            background: url('module/images/homepage/menubottom.gif')
                 no-repeat bottom left #f5f5f5;
        }
       
         .pages .close {
            float: right;
        }
       
        .pages a.element {
            color: black;
            font-size: 13px;
            font-weight: bold;
            margin-bottom: 3px;
            text-decoration: none;
             display: block;
        }
       
        .pages a.element:hover {
            text-decoration: underline;
             background: url('module/images/homepage/croixnoire.gif') 223px
                3px no-repeat;
        }
       
         .pages .close {
            float: right;
            width: 13px;
            height: 11px;
        }
       
         .right {
            float: right;
        }
       
         a.bouton {
            color: white;
            font-size: 12px;
            font-weight: bold;
            text-transform: uppercase;
            margin-right: 10px;
            padding: 2px 5px;
            text-decoration: none;
            font-family: calibri;
            border: 1px solid #909090;
             text-align: center;
        }
       
         a.bouton.bleu {
            background: #0099cb;
        }
        
        a.bouton.bleu:hover {
            background: #0fb3e9;
        }
       
        a.bouton.vert {
             background: #4ba600;
        }
       
         a.bouton.vert:hover {
            background: #5cc803;
        }
    </ui:style>
    <g:HTMLPanel styleName="{style.menu}">
       <div class="{style.close}">
            <a href="#">
               <img src="module/images/homepage/croix.gif" border="0" />
            </a>
        </div>
       <h2><g:InlineLabel  ui:field="userLabel">Jean-Pierre Dupont</g:InlineLabel></h2>
        <div class="{style.pages} {style.selected}">
            <a href="#" class="{style.element}">
                <img src="module/images/homepage/1ptrans.gif" border="0"
                    class="{style.close}" />
                Ma page personnel(0)
            </a>
        </div>
         <div class="{style.pages}">
            <a href="#" class="{style.element}">
                <img src="module/images/homepage/1ptrans.gif" border="0"
                    class="{style.close}" />
                Autre page (0)
            </a>
        </div>
        <br />
        <g:Anchor ui:field="newButton" href="#" styleName="{style.bouton} {style.bleu}">
            Créer une nouvelle page
        </g:Anchor>
         <g:TextArea ui:field="noteTextArea">
            Ici je peux mettre des notes
         </g:TextArea>

        <g:Anchor ui:field="saveNoteButton" href="#" styleName="{style.bouton} {style.vert} {style.right}">
            Enregistrer
        </g:Anchor>
     </g:HTMLPanel>
</ui:UiBinder>


Puis on modifie la classe associée de la manière suivante:
/**
*
*/
package module.client.homepage.menu;

import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;

/**
*
*
*/
public class HomePageMenu extends Composite {

    private static HomePageMenuUiBinder uiBinder = GWT
             .create(HomePageMenuUiBinder.class);

    interface HomePageMenuUiBinder extends UiBinder<Widget, HomePageMenu> {
    }

    //Composant GWT que l'on veux utiliser lié avec l'attribut ui:field=""
    @UiField InlineLabel userLabel;
    @UiField Anchor newButton;
    @UiField TextArea noteTextArea;
    @UiField Anchor saveNoteButton;

    public HomePageMenu() {
         initWidget(uiBinder.createAndBindUi(this));
    }

    @UiHandler("newButton")
    public void onNewClick(ClickEvent event){
        //Création d'une nouvelle page
    }
   
    @UiHandler("saveNoteButton")
    public void onNewClick(ClickEvent event){
        saveNote(noteTextArea.getText());
    }

    public void setUserName(String userName){
        userLabel.setText(userName);
    }

}

Comme on a pu le voir, il est très simple d’intégrer des maquettes HTML/CSS en GWT abec UiBinder, ce qui n’était pas le cas avant la version 2 de GWT. Cela permet d’améliorer la collaboration entre le Web Designer et le développeur puisqu’ils utilisent un langage commun le XML/HTML pour réaliser les écrans. Cela permet également au Web Designer, après une rapide prise en main des outils type SVN/Eclipse, de pouvoir intervenir sur le design de l’application directement sans aucune aide du développeur.

Dans notre cas, on a eu l’agréable surprise de voir notre Web Designer créer des écrans GWT lui même, les modifier et même coder en java pour interagir avec l’IHM; modifier un style programmatiquement ou déclencher une action simple.

lundi 8 novembre 2010

Retour d'expérience d'un projet GWT : 2 UiBinder, enfin une forte collaboration entre le designer et le développeur (2/8)

Le contexte:

Le projet a pour but d'améliorer l'ergonomie et l'usabilité du back office d’un produit en cours de développement réalisé en collaboration avec SFEIR

Dans le cadre de ce projet, la version de GWT utilisée passe de la 1.7.1 à la 2.0.3 afin de bénéficier des nouvelles fonctionnalités offertes par cette version. De nouveaux pattern de développement ont également été mis en place au cours de ce projet.

Voici une série d'article sur les nouveautés de GWT 2, les choix d'architectures, et bibliothèques utilisés qui font part de notre retour d'expérience sur le sujet. Ces articles ont été écris par David Aboulkheir, Patrice de Saint Steban et Cyril Lakech

  1. Nouveautés de GWT 2.0
  2. UiBinder, enfin une forte collaboration entre le designer et le développeur
  3. Intégration facile de maquette Html en GWT 2
  4. Architecture Modèle-Vue-Presenteur
  5. Implémentation Modèle-Vue-Présenteur
  6. Ecrire des tests unitaires avec Mockito
  7. Mise en place de Gin sur le projet
  8. Internationalisation

UiBinder, enfin une forte collaboration entre le designer et le développeur

Dans la version 2 de GWT, Google propose aux développeurs de choisir comment coder les écrans, soit en Java uniquement comme c'était le cas jusqu'à présent soit en utilisant une nouvelle fonctionnalité UiBinder, qui permet de coder les écrans en XML, très proche du HTML.

UiBinder permet d'écrire les interfaces graphiques avec un formalisme XML un peu comme on peut le faire avec JSF, Flex, Silverlight ou encore en HTML. Jusque-là, la création d'interface en GWT se faisait en manipulant du code java à la façon native de Swing ou SWT/JFace. On va maintenant pouvoir les écrire en XML et les lier (les binder) avec une classe java qui contiendra le code de notre vue. Le code en sera d'autant plus lisible, maintenable et plus rapide à développer. Cette évolution va permettre également la multiplication d'outils puissants, comme les éditeurs d'interfaces GWT, plus simples à créer, comme GWTDesigner d'Instantiations, qui a été acheté par Google et qui est maintenant disponible gratuitement: http://code.google.com/intl/fr/webtoolkit/tools/download-gwtdesigner.html

Cette nouvelle organisation, sépare la partie présentation (l'écran) de la partie contrôle (le code java). On écrit un fichier XML contenant nos widgets graphiques, puis on les associe avec les objets dans notre classe java où l'on ajoute aussi les évènements de l'IHM. Il est également possible d'écrire notre interface en HTML en y incorporant nos widgets HTML. Le CSS peut se trouver directement dans le fichier d'interface ou dans un ClientBunddle (système GWT2 de gestion des ressources type CSS en java qui sera détaillé ci-dessous).

Prenons une classe Miniature.java, qui permet d'afficher une image et son titre, pour utiliser UIBinder. Commençons par créer le fichier xml :

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:gwt='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
   .mini {
    float : left;
    margin: 20px;
    height: 150px;
    width: 150px;
   }
</ui:style>
   <gwt:VerticalPanel styleName="{style.mini}">
        <gwt:Image ui:field="miniature" />
       <gwt:Label ui:field="label"/>
   </gwt:VerticalPanel>
</ui:UiBinder>

Nous voyons ici, que la racine du XML, ui:UiBinder permet de configurer les namespaces pour utiliser les composants, le namespace "ui" contient les configurations du UiBinder, tandis que le namespace "gwt" permet d'utiliser les composants de base de GWT. La balise <ui:Style> permet d'insérer le CSS utilisé par notre composant. Dans la suite du fichier, on peut accéder à la classe CSS en utilisant la syntaxe {style.nomClasse}. Nous voyons ensuite que le composant GWT racine est le VerticalPanel qui contient une Image et un Label. Pour les composants Image et Label, on a ajouté un attribut ui:field associé à un nom de paramètre, ce qui nous permettra d'accéder au composant depuis notre classe Java.

Voyons maintenant la classe Java associée :

public class Miniature extends Composite {
    interface Binder extends UiBinder<Widget, Miniature> { }

    private static final Binder binder = GWT.create(Binder.class);
    @UiField Image miniature;
    @UiField Label label;
    private String destination;

    public Miniature(String url, String titre, String destination) {
        this.destination = destination;
        initWidget(binder.createAndBindUi(this));
        miniature.setUrl(url);
        label.setText(titre);
    }

    @UiHandler("miniature")
    public void onClick(ClickEvent event) {
        Window.open(destination, "Image", "width=200, height=100");
    }
}

L'interface Binder étend UiBinder qui prend deux paramètres de type, le composant de base de notre interface (VerticalPanel dans notre cas, mais nous utilisons une super classe), et la classe qui va contenir les composants reliés (La classe actuel). Nous créons ensuite, en variable static, une instance de cette interface en utilisant GWT.create(); C'est le compilateur de GWT qui s'occupera d'implémenter cette classe en utilisant les informations du fichier XML.

Puis nous ajoutons les champs de notre interface en utilisant l'annotation @UiField pour indiquer à GWT qu'il faut relier ces champs avec les composants GWT définis dans le fichier XML. Le nom du champ doit être celui donné dans l'attribut ui:field. Dans notre constructeur, nous appelons la methode createAndBindUi sur notre interface Binder, qui va alors créer et relier les composants GWT à notre classe. Enfin, la methode onClick, appelée lors du clic sur l'image, est reliée à notre composant miniature grâce à l'annotation @UiHandler("miniature").

UiBinder permet aussi de créer une interface en HTML et d'y intégrer nos composants GWT sans passer par les traditionnels composants Panel de GWT (VerticalPanel, Grid, ...), tout simplement en utilisant le composant HTMLPanel. Utilisons ce procédé pour refaire le formulaire de recherche :

<?xml version="1.0" encoding="UTF-8"?>
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
    xmlns:gwt='urn:import:com.google.gwt.user.client.ui'>
    <ui:style>
        .label {
            float: left;
            width: 50px;
            clear: both;
        }
        .element {
            float: left;
            width: 250px;
        }
</ui:style>
    <gwt:HTMLPanel>
        <dl>
            <dt class='{style.label}'>
                <ui:msg>Topic :</ui:msg>
            </dt>
            <dd class='{style.element}'>
                <gwt:TextBox ui:field="saisieSujet" />
            </dd>
            <dt class='{style.label}'>
            </dt>
            <dd class='{style.element}'>
                <gwt:Button ui:field="boutonAjouter">
                    <ui:msg>Search</ui:msg>
                </gwt:Button>
            </dd>
        </dl>
    </gwt:HTMLPanel>
</ui:UiBinder>

Ici, la classe Java est sensiblement équivalente à la classe Miniature.java :

public class FormulaireRecherche extends DialogBox {
    interface Binder extends UiBinder<Widget, FormulaireRecherche> {}
    private static final Binder binder = GWT.create(Binder.class);

    @UiField Button boutonAjouter;
    @UiField TextBox saisieSujet;

    public FormulaireRecherche() {
        super(true);
        add(binder.createAndBindUi(this));
        center();
    }

    @UiHandler("boutonAjouter")
    public void onClick(ClickEvent event) {
        hide();
    }
}

Références :

lundi 25 octobre 2010

Retour d'expérience d'un projet GWT : 1 Nouveautés de GWT 2.0 (1/8)

Le contexte:

Le projet a pour but d'améliorer l'ergonomie et l'usabilité du back office d’un produit en cours de développement réalisé en collaboration avec SFEIR

Dans le cadre de ce projet, la version de GWT utilisée passe de la 1.7.1 à la 2.0.3 afin de bénéficier des nouvelles fonctionnalités offertes par cette version. De nouveaux pattern de développement ont également été mis en place au cours de ce projet.

Voici une série d'article sur les nouveautés de GWT 2, les choix d'architectures, et bibliothèques utilisés qui font part de notre retour d'expérience sur le sujet. Ces articles ont été écris par David Aboulkheir, Patrice de Saint Steban et Cyril Lakech

  1. Nouveautés de GWT 2.0
  2. UiBinder, enfin une forte collaboration entre le designer et le développeur
  3. Intégration facile de maquette Html en GWT 2
  4. Architecture Modèle-Vue-Presenteur
  5. Implémentation Modèle-Vue-Présenteur
  6. Ecrire des tests unitaires avec Mockito
  7. Mise en place de Gin sur le projet
  8. Internationalisation

1 Nouveautés de GWT 2.0

Development Mode (anciennement OOPHM : "Out Of Process Hosted Mode")

GWT 2.0 apporte une nouvelle approche du développement des applications GWT en permettant de débugguer le code java et de voir le résultat directement dans les navigateurs sans passer par un navigateur spécifique, anciennement via le HostedMode qui utilisait son propre Navigateur différent selon le système d'exploitation. On assiste ainsi à un changement de terminologies puisqu'il ne faut plus parler de "hosted mode", qui portait souvent à confusion, mais de "development mode". Et pour la même raison on parle maintenant de "production mode" au lieu de "web mode", pour parler du script compilé.

On peut ainsi utiliser les outils du navigateur pour développer comme par exemple firebug sans devoir recompiler en permanence toute l'application. Pour utiliser ce mode, il suffira de copier/coller l'url qui est donnée par GWT lors du démarrage du server dans le navigateur, par exemple: "http://localhost:8080/Tutoriel.html?gwt.hosted=X.X.X.X:NNNN", où les X représentent l'adresse IP de votre ordinateur et les N le port utilisé par GWT.

Le development mode a été pour nous un facteur de gain de productivité important par rapport au hosted mode car grace à cette fonctionnalité il est possible de tester directement l’application dans les navigateurs cibles. On regrettera simplement que cette fonctionnalité ne soit pas disponible dans Chromium, le projet open-source de Google Chrome sur Linux. Layout

La notion de Layout permet d'avoir des composants génériques pour gérer la disposition des widgets. Ces layouts utilisent des panels déjà existant mais uniformisent leur utilisations. De plus, ces layouts se redimensionnent automatiquement en réorganisant plus précisément les widgets. Le rendu a été amélioré pour s'afficher plus rapidement et le redimensionnement peut être animé. A la différences des anciens panels de GWT qui utilisent massivement les tableaux pour afficher les widgets, les nouveaux layouts utilisent uniquement le CSS. Il existe par exemple le StackLayoutPanel, le TabLayoutPanel ou le DockLayoutPanel qui permettent d'avoir un contenu principal (Center) et d'ajouter des contenus au Nord, au Sud, à l'Ouest et à l'Est autour de celui-ci.

Nous avons utilisé ces Layout dans l’application très simplement et notre Web Designer a été particulièrement content de voir le rendu HTML/CSS généré s’améliorer en les utilisant, ce qui a faciliter son travail.

RPC (Remote Precedure Call)

Le système de service distant a été refondu pour gagner en performance et permettre l'ajout de nouvelles fonctionnalités. Pour le développeur, le principe de fonctionnement ne change pas. Il suffit d'ajouter dans le fichier Tutoriel.gwt.xml la ligne <inherits name='com.google.gwt.rpc.RPC' /> et de changer l'interface RemoteService par RpcService ainsi que la classe RemoteServiceServlet par RpcServlet. Cependant, cette fonctionnalité n'est pas, pour l'instant, compatible avec Google App Engine.

ClientBundle

On avait vu que GWT dans ses versions précédantes était capable de réunir plusieurs images en une seule, GWT 2.0 va encore plus loin car il est maintenant capable de réunir différents types de ressources (Images, Texte, Css, Données, etc...) en même temps. Toutes les ressources sont intégrées dans un même bundle encodé en base 64. Rappelons ainsi l'avantage de ce concept: un seul fichier à télécharger, donc, moins de requêtes HTTP et un temps de chargement de la page plus rapide.

Code splitting

Tout le code javascript est compilé en un seul fichier, téléchargé au chargement de la page. Dans le cas de très grosses applications, la taille de celui-ci peut considérablement devenir très importante et ralentir, de ce fait, le temps de chargement de l'application au démarrage. Pour pallier à ce problème, GWT 2.0 offre maintenant la possibilité de couper notre application en plusieurs fichiers qui seront téléchargés quand ceux-ci seront nécessaires. Par exemple, si une partie du code est utilisé uniquement lors du déclenchement d'un événement, son téléchargement n'est pas forcément essentiel lors du premier chargement de l'application. Par ailleurs l'utilisation est très simple:

GWT.runAsync(new RunAsyncCallback() {
    @Override
    public void onSuccess() {
        //Tout le code qui est ici, sera téléchargé plus tard.
    }

    @Override
    public void onFailure(Throwable reason) {
        //Si le téléchargement du nouveau code a échouée
    }
});

Mais attention, si le code, qui se trouve dans le onSuccess, est aussi utilisé par l'application dès son lancement, il sera téléchargé au début. C'est pourquoi GWT génère, tout de même, un rapport qui donne toutes les informations de compilation, informations que l'on peut analyser pour optimiser son application.

De plus, il est important de prévenir l'utilisateur du chargement par une barre de progression, ou par une icône de préchargement, car le changement n'est pas forcement immédiat et peut influer sur l'utilisabilité de l'application. Pour utiliser cette fonctionnalité, ajoutez "-compileReport" dans les paramètres avancés du compilateur GWT. Les rapports de compilation sont alors générés dans le répertoire extras/[moduleName]/soycReport/compileReport/.

Nous avons utilisé cette fonctionnalité pour charger à la demande les écrans principaux de l’application. Nous avons constater que la taille globale des fichiers javascript générés a sensiblement augmentée suite a la mise en place du Code Splitting. Il faut noter que l’utilisation de cette fonctionnalité sur 12 permutations a nécessité dans notre cas d’augmenter la partition /tmp utilisée pour compiler l’application (4Go ne suffisait pas).