Présentation dans le but d\'approfondir les connaissances sur GWT dans le cadre du cours combiné GTI780 / MTI780, Sujets spéciaux en TI, donné par Claude Coulombe, à l'Ecole de technologie supérieure, Montréal, Automne 2008
1. Google Web Toolkit (GWT):
approfondissement
Sujets spéciaux en TI
Le Web 2.0 : concepts et outils
École de technologie supérieure
par
Claude Coulombe
GTI-780 / MTI-780 Montréal, novembre 2008
2. But
Dans cette présentation vous approfondirez
votre connaissance du Google Web Toolkit
(GWT) qui permet le développement rapide
en Java d'applications Web 2.0 et AJAX.
http://code.google.com/webtoolkit/
GTI-780 / MTI-780 Montréal, novembre 2008
4. Transcompilateur Java à JavaScript
GWT version 1.4 supporte :
* Firefox 1.0, 1.5, 2, 3.x
Java * Internet Explorer 6, 7
* Safari 2.0, 3.0
* Opera 9.0
Write Once...
JavaScript
Run Everywhere!
GTI-780 / MTI-780 * Source Clipart : http://www.clipart.com Montréal, novembre 2008
5. Transcompilateur Java à JavaScript
Transcompilateur GWT prend du code-client en Java et
le traduit en JavaScript optimisé
JavaScript vu comme le code assembleur du fureteur
Élimination du code non-utilisé dans les bibliothèques,
inférence de type, retrait du polymorphisme,
compression “agressive” du code, « Obfuscation »
Le JavaScript produit est généralement plus rapide
que du JavaScript écrit à la main*
Emploi de la liaison différée (“Deferred Binding”) pour
produire du code JavaScript optimal pour chaque
fureteur (i.e. génère du code spécifique à chaque
fureteur)
« Ne payez que pour ce que vous utilisez »
GTI-780 / MTI-780 * Note : sauf si code < 100 lignes Montréal, novembre 2008
6. Transcompilateur – Liaison différée
Générer du code optimal et spécifique à chaque fureteur
Copyright Google 2008
GTI-780 / MTI-780 * Source : http://www.google.com Montréal, novembre 2008
7. Transcompilateur Java à JavaScript
Du JavaScript plus rapide que du code écrit à la main !!!
Ainsi, ceci
public static void onModuleLoad() {
Button b = (new Button()).Button();
b.setText(quot;Java vers JavaScriptquot;);
}
après compilation donnera quelque chose comme cela...
function onModuleLoad(){
var b;
b = $Button(new Button());
$setInnerText(b.element, 'Java vers JavaScript');
}
GTI-780 / MTI-780 * Note : -style : OBFUSCATED, DETAILED, PRETTY Montréal, novembre 2008
8. Transcompilateur Java à JavaScript
Code Java
MonProjet.
java
Code
JavaScript
MonProjet.
js
Ressources
MonProjet.
html
Ressources
MonProjet.css,
MonProjet.
.png, .jpg, .gif Transcompilateur html
MonProjet.css,
.png, .jpg, .gif
Configuration
Module
MonProjet.g
wt.xml
Autres .jar
Gwt-dev-
gwt-user.jar Compatibles
windows.jar
avec GWT
GTI-780 / MTI-780 Montréal, novembre 2008
9. Transcompilateur – Code optimisé!
Copyright Google 2008
« Ne payez que pour ce que vous utilisez »
GTI-780 / MTI-780 * Source : http://www.google.com Montréal, novembre 2008
10. Emulation – JRE (Java Runtime Environment)
Le transcompilateur de GWT fournit l'émulation en
JavaScript d'un sous-ensemble du langage Java (JRE)
généralement utilisé pour la programmation de base
java.lang, java.util, java.io, java.sql
Restriction pour le code client
devant être traduit en JavaScript.
Aucune restriction n'est imposée
du côté du code serveur.
Java (JSP/JSF/Servlet), PHP,
ASP .NET, Perl, RoR, Python, Perl, ...
GTI-780 / MTI-780 * Source image : http://www.sun.com Montréal, novembre 2008
11. JSNI : JavaScript Native Interface
GWT permet l'intégration facile avec des bibliothèques
JavaScript externes grâce à son JavaScript Native
Interface (JSNI)
Interagir directement avec JavaScript (accès natif) à
partir de Java et vice-versa
Inclusion automatique des bibliothèques JavaScript
GWT 1.5 introduit le concept de JavaScript Overlay
pour simplifier l'intégration de prototypes JavaScript
dans GWT
GTI-780 / MTI-780 Montréal, novembre 2008
12. JSNI : JavaScript Native Interface
GWT permet l'intégration facile avec des bibliothèques
JavaScript externes grâce à son JavaScript Native
Interface (JSNI)
Interagir directement avec JavaScript à partir de Java
et vice-versa
Inclusion automatique des bibliothèques JavaScript
// Déclaration de la méthode en Java...
native String inverserNomPrenom(String nom)
/*-{
// Implémentation en JavaScript
var re = /(w+)s(w+)/;
return name.replace(re, '$2, $1');
}-*/;
GTI-780 / MTI-780 Montréal, novembre 2008
13. JSNI : Type Overlay JavaScript
GWT 1.5 introduit le concept de JavaScript Overlay pour simplifier
l'intégration de prototypes JavaScript dans GWT
Une structure de données JSON (JavaScript Object Notation)
var electionsJSON = [
{ quot;Prenomquot; : quot;Paulinequot;, quot;NomFamillequot; : quot;Maroisquot; }, { quot;Prenomquot; : quot;Amirquot;, quot;NomFamillequot; : quot;Khadirquot; },
{ quot;Prenomquot; : quot;Marioquot;, quot;NomFamillequot; : quot;Dumontquot; }, { quot;Prenomquot; : quot;Jeanquot;, quot;NomFamillequot; : quot;Charestquot; }
];
// Un type Overlay JavaScript
class PoliticienQC extends JavaScriptObject {
// Un type Overlay JS a toujours un constructeur protected, à zéro argument
protected PoliticienQC() { }
// Les méthodes dans un Overlay JavaScript sont en JSNI
public final native String getPrenom() /*-{ return this.Prenom; }-*/;
public final native String getNomFamille() /*-{ return this.NomFamille; }-*/;
// Notez, toutefois, que toutes les méthodes ne sont pas obligatoirement en JSNI
public final String getNomComplet() {
return getPrenom() + quot; quot; + getNomFamille();
}
}
GTI-780 / MTI-780 * Source : http://googlewebtoolkit.blogspot.com Montréal, novembre 2008
14. JSNI : Type Overlay JavaScript
// Obtenir un prototype JavaScript pour l'Overlay
class MonModuleEntryPoint implements EntryPoint {
public void onModuleLoad() {
PoliticienQC p = getPremierPoliticien();
// Youppi! Maintenant j'ai un prototype JavaScript qui est aussi un PoliticienQC
Window.alert(quot;Bonjour, quot; + p.getPrenom());
}
// Utilisation de JSNI pour obtenir le prototype JSON que nous désirons
// Le prototype JSON object reçoit un type Java implicitement
// en se basant sur le type retourné par la méthode
private native PoliticienQC getPremierPoliticien() /*-{
// Obtenir une référence au premier PoliticienQC dans le tableau JSON
return $wnd.electionsJSON[0];
}-*/;
}
GTI-780 / MTI-780 * Source : http://googlewebtoolkit.blogspot.com Montréal, novembre 2008
15. GWT – Structure bibliothèque & API
GTI-780 / MTI-780 * Source Clipart : http://www.clipart.com Montréal, novembre 2008
16. GWT – Structure bibliothèque & API
La structure du gwt-user.jar de GWT 1.5.3 Note : Transcompilateur GWT
Trans
dans gwt-dev-windows.jar
compilateur
Interface Java à Bibliothèque
Native JavaScript d'émulation
JavaScript
JRE
JSNI
GWT API
Bibliothèque
Communication
IUG Analyseur Gestion de Intégration
avec le serveur
Widgets & XML l'historique à JUnit
RPC & Ajax
Panels
GTI-780 / MTI-780 Montréal, novembre 2008
17. GWT – Structure bibliothèque & API
La structure du gwt-user.jar de GWT 1.5.3
Cinq grandes catégories :
- interface utilisateur
- user.client.ui, dom, animation, user.theme
- communication client-serveur
- http.client, user.client.rpc, user.server.rpc
- format des données échangées
- xml, json
- émulation JRE (emul)
- java.io, java.lang, java.sql, java.util
- utilitaires
- i18N, junit, benchmarks, user.tools
GTI-780 / MTI-780 Montréal, novembre 2008
18. Bibliothèque de composants IU
Bibliothèque de composants d'interface-utilisateur analogue
à SWING qui facilite le développement d'une interface-
client qui fonctionne dans tous les fureteurs
Manipulation du DOM en Java
Gestion des événements
Support des CSS
I18N
Support du glisser-déposer
GTI-780 / MTI-780 * Source Clipart : http://www.clipart.com Montréal, novembre 2008
19. Interface Utilisateur - Composants
Éléments statiques: étiquette (Label), HTML, Image, hyperlien (Hyperlink), champ
caché (Hidden)
Widgets (E/S) : bouton (Button), bouton poussoir (PushButton), bouton à bascule
(ToggleButton), case à cocher (CheckBox), bouton radio (RadioButton), menu
déroulant (ListBox), zone de texte (TextBox), zone de texte avec suggestions
(SuggestBox), zone d'entrée de mot de passe (PasswordTextBox), zone de texte
multiligne (TextArea), zone d'édition de texte enrichi (RichTextArea)
Widgets complexes : arbre (Tree), barre de menus (MenuBar), téléversement de
fichiers (FileUpload)
Panneaux de disposition simple : panneau en file (FlowPanel), panneau horizontal
(Horizontal Panel), panneau vertical (Vertical Pannel), panneau à coulisse
(HorizontalSplitPanel, VerticalSplitPanel), panneau HTML (HTMLPanel), panneau
superposé (DeckPanel)
Panneaux de disposition complexe : table flexible* (FlexTable), grille (Grid), panneau
polyptyque* (DockPanel), panneau à onglets (TabPanel), panneau en pile (StackPanel)
Panneaux conteneurs simples : panneau composite ou composite (Composite) panneau
simple (SimplePanel), panneau à barre de défilement (ScrollPanel), panneau de focus
(FocusPanel)
Panneaux conteneurs complexes : panneau de formulaire (FormPanel), panneau à
dévoilement* (DisclosurePanel), panneau surprise* (PopupPanel), boîte de dialogue
(DialogBox)
GTI-780 / MTI-780 http://gwt.google.com/samples/Showcase/Showcase.html Montréal, novembre 2008
20. Gestion des événements
GWT utilise le concept de récepteur (« listener interface »)
pour traiter les événements
Semblable à d'autres canevas d'applications graphiques
comme SWING
Le récepteur via l'interface “listener interface” définit une
ou plusieurs méthodes que le widget appelle en réaction à
un événement
Button unBouton = new Button(quot;Cliquez moi!quot;);
unBouton.addClickListener(new ClickListener() {
public void onClick(Widget emetteur) {
// traitement du Clic
}
});
GTI-780 / MTI-780 Montréal, novembre 2008
21. Interface Utilisateur - Composants
Bouton (Button)
// Création d'un bouton qui réagit à un clic grâce à un récepteur de clic
Button bouton = new Button(quot;Cliquez-moiquot;, new ClickListener() {
public void onClick(Widget sender) {
Window.alert(quot;Bonjour GWTquot;);
}
});
GTI-780 / MTI-780 Montréal, novembre 2008
22. Interface Utilisateur - Composants
Case à cocher (CheckBox)
// Création d'une case à cocher
CheckBox caseResidentMtl = new CheckBox(quot;Résident de Montréalquot;);
// La case est cochée par défaut
caseResidentMtl.setChecked(true);
// Attacher un récepteur de clic à la case
caseResidentMtl.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
boolean estMontrealais = ((CheckBox) sender).isChecked();
Window.alert( (estMontrealais ? quot;quot; : quot;nonquot;) + quot; Montréalaisquot;);
}
});
GTI-780 / MTI-780 Montréal, novembre 2008
23. Interface Utilisateur – Bouton radio
Bouton radio (RadioButton)
// Création d'un groupe de boutons radio
RadioButton rbBleu = new RadioButton(quot;groupeRbCouleursquot;, quot;bleuquot;);
RadioButton rbBlanc = new RadioButton(quot;groupeRbCouleursquot;, quot;blancquot;);
RadioButton rbRouge = new RadioButton(quot;groupeRbCouleursquot;, quot;rougequot;);
// Cocher le bouton bleu par défaut
rbBleu.setChecked(true);
// Ajouter le groupe de boutons radio à un panneau
FlowPanel panneau = new FlowPanel();
panneau.add(rbBleu);
panneau.add(rbBlanc);
panneau.add(rbRouge);
GTI-780 / MTI-780 Montréal, novembre 2008
24. Support des CSS
Séparation du code et de la présentation
Code Java :
public ListWidget(String Item) {
...
setStyleName(“gwt-ListWidget”);
}
Fichier CSS :
.gwt-ListWidget {
background-color:black;
color:lime;
}
GTI-780 / MTI-780 Montréal, novembre 2008
25. Support des CSS - conseils
Code Java : (usage de CSS primaire et dépendant)
MonPetitWidget monPW = new MonPetitWidget();
monPW.setStylePrimaryName(quot;monPetitWidgetquot;);
monPW.addStyleDependentName(quot;selectedquot;);
Fichier CSS :
.monpetitWidget {
background-color:black;
color:lime;
}
.monPetitWidget .monPetitWidget-selected {
color:red;
}
Permet de faire varier facilement l'apparence en fonction de l'état
Note : Ne pas utiliser les CSS pour la disposition (ex.
.monPetitWidget { position: absolute; } )
GTI-780 / MTI-780 Montréal, novembre 2008
27. I18N
Le transcompilateur GWT utilise la liaison différée
(« Deferred Binding ») pour générer une version
différente de l'application Web pour chaque langue
Par exemple, puisque GWT supporte 4 navigateurs
différents, si votre application doit fonctionner en
3 langues, le transcompilateur de GWT produira
12 versions différentes de votre application au
moment de la compilation
À l'exécution, GWT choisira la bonne version de
l'application à montrer à l'utilisateur
GTI-780 / MTI-780 Montréal, novembre 2008
28. I18N – mécanismes de localisation
“Constants” pour des chaînes constantes et des
réglages
“Messages” pour les chaînes avec des arguments
“DateTimeFormat” pour les dates et l'heure
“NumberFormat” pour les nombres et les unités
de mesure
Pas de processus dynamique (tout est statique et
fait à la compilation), sinon il faut développer son
propre mécanisme
GTI-780 / MTI-780 Montréal, novembre 2008
29. GUI – Patrons de conception
GTI-780 / MTI-780 * Source Clipart : http://www.clipart.com Montréal, novembre 2008
30. GUI – Patrons de conception - MVC
Patron MVC
Client MVC
Vue:
Présentation découplée
Affiche les
informations et événements Échages de
achemine les
actions de l'usager
V C données
no
no
mise à jour
s
ée
tiif
t fi
nn
ica
Contrôleur:
ca
ac aux
es r
ac ux
t d jou
do
tiio
to
c è do
c è do
a
n
n Établit les liens
s e nn
en à
s
m e
entre le Modèle et
ge mis
n née
M
llec es
n
la Vue
tu
tu
é
re
re
an
s
Reçoit les
ch événements de la
Modèle:
Vue et gère les
Données de l'application actions de l'usager
(POJOs) Notifie les
changements du modèle
par des événements
transmis aux vues
abonnées
GTI-780 / MTI-780 Montréal, novembre 2008
31. GUI – Patrons de conception - Observateur
Le Modèle utilise le patron de conception Observateur (Observer Pattern) pour informer la
Vue/Contrôleur du changement des données et bien découpler la Vue du Modèle
Ainsi, différents éléments du Modèle servent de sujets ou données observables (Subjects) à
un ensemble d'observateurs (Observers) contenus dans les Vues/Contrôleurs qui sont en
quelque sorte abonnés aux modifications des données du modèle.
Programmation événementielle qui favorise un découplage des composants
Compromis entre un petit nombre d'événements généraux du genre « quelque chose » a
changé dans le modèle (granularité grossière) et un grand nombre de petits événements
reliés à des éléments très précis du modèle (granularité fine).
GTI-780 / MTI-780 * Source figure : R. Dewsbury 2008 – Chap.2, p.96 Montréal, novembre 2008
32. GUI – Patrons de conception - Composite
Patron Composite (ou Object Composite)
* Source : http://www.google.com
* Source : http://fr.wikipedia.org/wiki/Objet_composite
Facilite la création de Widgets
S'utilise chaque fois qu'on crée un nouveau widget à partir de widgets existants
Offre un meilleur contrôle sur l'API exposé
Généralement préférable à l'utilisation de l'héritage
GTI-780 / MTI-780 Montréal, novembre 2008
33. GUI – Patrons de conception - Composite
class MonPremierComposite extends Composite {
private VerticalPanel conteneur = new VerticalPanel();
private Label monTitre = new Label();
private TextBox maZoneTexte = new TextBox();
// Constructeur
public MonPremierComposite() {
conteneur.add(monTitre);
conteneur.add(maZoneTexte);
initWidget(conteneur);
}
}
GTI-780 / MTI-780 Montréal, novembre 2008
34. GUI – Règle de codage – Accès aux éléments
Chaque composant « modifiable » d'une vue est muni
d'un accesseur et d'un test d'existence.
public Label getNom() {
if ( this.nom == null ) {
this.nom = new Label(“”);
}
return this.nom;
}
GTI-780 / MTI-780 Montréal, novembre 2008
37. Communication client-serveur & Ajax
Le RPC (« Remote Procedure Call »), appel de procédure à
distance
RPC rend facile l'échange d'objets Java (sérialisés) entre le code-
client et le code-serveur
Fournit une procédure automatique de sérialisation des objets
Autres outils Ajax :
HTTPRequest
RequestBuilder
FormPanel
Support de :
XML
JSON (JavaScript Object Notation)
GTI-780 / MTI-780 Montréal, novembre 2008
39. RPC (Remote Procedure Call)
GWT offre le très utile mécanisme du RPC (Remote Procedure Call),
comme moyen de communiquer avec les services hébergé sur un serveur JEE
J
Client et serveur parlent alors le même langage, i.e. le Java
GTI-780 / MTI-780 * Source : http://www.google.com Montréal, novembre 2008
40. RPC (Remote Procedure Call)
Un objet Java MesDonneesDO à échanger
import com.google.gwt.user.client.rpc.IsSerializable;
public class MesDonneesDO implements IsSerializable {
//...
}
Une première interface définit le service
import com.google.gwt.user.client.rpc.RemoteService;
public interface MonService extends RemoteService {
MesDonneesDO getReponseMonService(String requete);
}
Une deuxième interface dite asynchrone spécifie getReponseMonservice( ) mais
avec un paramètre supplémentaire sous la forme d'une procédure de rappel («
Callback ») que le code-client utilisera pour appeler le service.
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface MonServiceAsync {
public void getReponseMonService(String requete,
AsyncCallback maProcedureDeRappel);
}
GTI-780 / MTI-780 Montréal, novembre 2008
41. RPC - Code-serveur
Classe à implémenter du côté serveur hérite de com.google.gwt.user.server.rpc.RemoteServiceServlet
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import qc.ets.web2.gwt.client.MesDonneesDO;
import qc.ets.web2.gwt.client.MonService;
public class MonServiceImpl extends RemoteServiceServlet implements MonService {
public MesDonneesDO getReponseMonService(String requete) {
if (requete.length() < 1) {
throw new IllegalArgumentException(quot;Requete invalide.quot;);
}
MesDonneesDO resultat = new MesDonneesDO();
resultat.setDonnees(quot;...quot;);
if ( isInvalide( resultat )) {
return null;
}
return resultat;
}
public boolean isInvalide(MesDonneesDO resultat) {
Return true; // à modifier
}
}
GTI-780 / MTI-780 Montréal, novembre 2008
42. RPC - Code-client
Le client n'est pas encore connecté au service. Nous pouvons faire cela en ajoutant un
récepteur (Listener) à un élément de l'interface, ce qui peut être fait avec une classe interne.
import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.client.rpc.ServiceDefTarget; import qc.ets.web2.gwt.client.MesDonneesDO;
import qc.ets.web2.gwt.client.MonService; import qc.ets.web2.gwt.client.MonServiceAsync;
public class MonClientRPC implements EntryPoint {
public void onModuleLoad() {
final Button bouton = new Button(quot;Appel RPCquot;);
final MonServiceAsync serviceProxy = (MonServiceAsync)GWT.create(qc.ets.web2.gwt.client.MonService.class);
ServiceDefTarget pointService = (ServiceDefTarget) serviceProxy;
pointService.setServiceEntryPoint(GWT.getModuleBaseURL() + quot;/reponseServicequot;);
bouton.addClickListener(new ClickListener( ) {
public void onClick(Widget emetteur) {
AsyncCallback maProcedureDeRappel = new AsyncCallback() {
public void onSuccess(Object resultat) {
MesDonneesDO resultatDO = (MesDonneesDO) resultat;
System.out.println(quot;*** SUCCES RPC ***nquot; + resultatDO.getDonnees());
}
public void onFailure(Throwable erreur) {
System.out.println(quot;*** ERREUR RPC ***quot; + erreur.getMessage());
}
};
serviceProxy.getReponseMonService(quot;Requete bidonquot;, maProcedureDeRappel);
}});
RootPanel.get(quot;emprise1quot;).add(bouton);
}
} GTI-780 / MTI-780 Montréal, novembre 2008
43. Gestion de l'historique du navigateur
La gestion de l'historique du navigateur s'occupe des
boutons « avancer » et « reculer » et des liens
Une API simple de gestion de l'historique basée sur
une pile de jetons
– Lorsque l'application démarre, la pile est vide
– Lorsque l'utilisateur clique sur quelque chose
• Vous pouvez ajouter des jetons sur la pile
History.newItem(“nouveauJeton”)
• Classe Hyperlink ajoute des jetons automatiquement
– Vous pouvez aussi réagir aux événements “History
events” en utilisant un HistoryListener
History.addHistoryListener(controle)
GTI-780 / MTI-780 Montréal, novembre 2008
44. Démo – Bâtir des applications GWT
GWT
en Action
GTI-780 / MTI-780 * Source Clipart : http://www.clipart.com Montréal, novembre 2008
45. Créer un squelette d'application GWT
GWT crée automatiquement un code-client
rudimentaire
Vous pouvez ensuite mettre de la chair sur ce
squelette dans le but de créer une application Web
plus sophistiquée
GWT
GTI-780 / MTI-780 * Source Clipart : http://www.clipart.com Montréal, novembre 2008
46. Créer un squelette d'application GWT
public class Bonjour implements EntryPoint {
public void onModuleLoad() {
Button bouton = new Button(quot;Cliquez-moi!quot;,
new ClickListener() {
public void onClick(Widget sender) {
Window.alert(quot;Bonjour GWTquot;);
}
});
RootPanel.get().add(bouton);
}
}
GTI-780 / MTI-780 Montréal, novembre 2008
47. Ressources - Livres
GWT in Action: Easy Ajax with the Google Web
Toolkit
par Robert Hanson, Adam Tacy
600 pages
Manning Publications
(5 juin, 2007)
www.manning.com/hanson/
Google Web Toolkit Applications
par Ryan Dewsbury
608 pages
Prentice Hall
(15 décembre, 2007)
www.gwtapps.com
GTI-780 / MTI-780 Montréal, novembre 2008
48. Ressources - Livres
Google Web Toolkit Solutions : More Cool &
Useful Stuff
par David Geary, Rob Gordon
408 pages
Prentice Hall
(17 novembre, 2007)
www.coolandusefulgwt.com
GWT in Practice
par Robert T. Cooper, Charlie E. Collins
358 pages
Manning Publications
(12 mai, 2008)
www.manning.com/cooper/
GTI-780 / MTI-780 Montréal, novembre 2008