Conférence
Demain, le vendredi 27 janvier 2012, Jean-Christophe Uhl, secrétaire général de la société UBI (Uhl Bonnaventure Informatique), présentera le centre de télétravail de Reichstett. C’est ce lieu de travail convivial, idéalement situé entre Haguenau et Strasbourg, qui a été choisi par l’équipe de GreenIvory pour organiser la plupart de ses réunions.

La présentation aura lieu à Haguenau dans le cadre d’un déjeuner débat organisé par le Business Club de la Sandlach. Rappelons que Jean-Georges Perrin, CEO de GreenIvory, participera aussi à cet évènement pour partager son expérience du Web.

Déjeuner débat organisé par le BUSINESS CLUB de la SANDLACH
« Qu’est-ce qui fait bouger le Web ? » Jean-Georges Perrin
« Visite du centre de télétravail de Reichstett » Jean-Christophe Uhl
27/01/2012: 11h30
Hôtel Ibis de Haguenau
Route de Bitche
67500 HAGUENAU
Tél. + 33 (0)3 88 73 76 30

GooglePlus
Déjà présent sur Facebook et Twitter, GreenIvory vient de rejoindre Google+.
Vous pouvez désormais suivre nos actualités sur ce réseau social.

Voici le lien: GreenIvory sur Google+

Jean-Georges Perrin, CEO de GreenIvory, partagera son expérience du Web dans le cadre de deux évènements proposés le vendredi 27 janvier 2012.

Petit-déjeuner thématique organisé par AD’MISSION
« La veille ou comment rester compétitif »
Dans notre économie rapide, la veille est devenue obligatoire pour rester compétitif. Malheureusement, le volume d’information et de sources productrices d’information ne cessent de croître. Dans une première partie, Jean-Georges Perrin dressera un panorama des outils gratuits et payants qui permettent de rester alerte. Dans la seconde partie de la conférence, il proposera un échange ludique et dynamique autour des bonnes pratiques dans ce domaine.
27/01/2012: 09h00-11h00
AD’MISSION
204, avenue de Colmar
67100 Strasbourg
Inscription par E-mail à strasbourg@admissions.fr dans la limite des places disponibles et au plus tard le 23/01/2012.

Déjeuner débat organisé par le BUSINESS CLUB de la SANDLACH
« Qu’est-ce qui fait bouger le Web ? »
Jean-Georges Perrin travaille dans le Web depuis 1994. Il a fait l’essentiel de sa carrière dans l’ingénierie logicielle et spécifiquement dans les outils de développement pour le web. La société GreenIvory (qu’il dirige) est spécialisée dans l’extraction et la valorisation d’informations issues du Web, principalement pour les utiliser dans le domaine de l’e-marketing. Au delà de services dans son domaine d’expertise, GreenIvory propose plusieurs outils e-marketing en mode SaaS.
27/01/2012: 11h30
Hôtel Ibis de Haguenau
Route de Bitche
67500 HAGUENAU
Tél. + 33 (0)3 88 73 76 30

Toute l’équipe de GreenIvory vous souhaite une bonne et heureuse année 2012 !

Quand l’équipe de GreenIvory a été informé de ce projet, notre engouement a été immédiat et nous avons décidé de transformer les Ignite « locaux » en Ignite Alsace. Aujourd’hui nous allons encore plus loin dans cette fête du web, de l’innovation et de la technologie au service de tous.

6 mois

d’abonnement VoiceObserver Business (valeur 162EHT)
à tous les participants de cet événement.

Comment obtenir cette offre ? Allez sur VoiceObserver.com, créer votre analyse d’e-réputation pour
surveiller vos marques et vos concurrents. Notez le nom de votre analyse et envoyez un mail à
support@greenivory.com avec comme sujet #mtdnp. Offre valable jusqu’au 31/12/2011.


6 mois

d’abonnement OnliGence Premium (valeur 36EHT)
à tous les fans de réseaux sociaux.

Comment obtenir cette offre ? Allez sur OnliGence.com et identifiez-vous. Mentionnez @OnliGence
dans un tweet. Devenez fan de la page OnliGence sur Facebook (http://facebook.com/OnliGence) et
mentionnez notre produit dans un commentaire. Offre valable jusqu’au 31/12/2011.


1 an

d’abonnement MashupXFeed Elite avec ProductBooster (valeur 5400EHT)
à un participant d’Ignite Alsace.

Comment obtenir cette offre ? Venez à Ignite Alsace #1, laissez votre nom et e-mail sur une feuille simple
ou laissez une carte de visite et nous tirerons au sort le gagnant à la fin de l’événement. Vous devez être
présent pour gagner.


1 an

d’abonnement VoiceObserver Elite (valeur 2340EHT)
à un participant d’Ignite Alsace.

Comment obtenir cette offre ? Venez à Ignite Alsace #1, laissez votre nom et e-mail sur une feuille simple
ou laissez une carte de visite et nous tirerons au sort le gagnant pendant l’événement. Vous devez être
présent pour gagner.

Beaucoup d’applications web sont désormais basées sur AJAX, et offrent ainsi une interface plus réactive et plus dynamique, en minimisant (voire supprimant) les rechargements de page : les données à affichées sont chargées en arrière-plan puis insérées dans la page web, à coup de JavaScript (manipulation du DOM).

Contrairement à une page web entièrement générée par le serveur, cette page doit alors faire preuve d’une intelligence supplémentaire afin de gérer l’état de l’application à chaque instant de son utilisation. Peu importe donc la technologie employée sur le serveur, on s’attarde donc à trouver une technologie évoluée coté client, forcément basée sur JavaScript, seul langage à être embarqué dans tous les navigateurs modernes. Ont alors vu le jour de multiples framework JavaScript, tels jQuery, MooTools, Prototype ou encore Scriptaculous.

Google a tenté une approche différente en proposant un framework Java, couplé à un traducteur Java vers JavaScript. Une réelle prouesse technique, qui promet une abstraction quasi-totale du navigateur. L’avantage est que le codage se fait en Java, langage plus rigoureux que JavaScript, et ainsi plus simple à débugguer.

Avec GWT, l’application web, c’est une page web. S’il y a différentes vues (un formulaire de création, une liste, …), c’est via le DOM qu’on affiche les widgets qu’il faut. Mais pour le navigateur, l’URL reste la même, et si on recharge la page, la vue peut alors être perdue. De la même manière, l’utilisation du bouton Précédent dans le navigateur ne permet pas de naviguer, comme sur un site web classique. Sauf si… Si on réussit à faire croire au navigateur que l’URL a changé sans recharger la page, ça peut marcher.

Les ancres dans les URL

Dans une URL, on peut faire référence à un élément de la page (identifié de manière unique par un attribut id) en suffisant l’URL par #<id de l’élément>. La navigateur va alors défiler la page jusqu’à ce que l’élément concerné soit visible (s’il l’est). Cela permet de naviguer au sein d’une même page, et c’est très souvent utilisé pour une table des matières en début de page. L’avantage est que le navigateur considère tout changement derrière le caractère # d’une URL (l’ancre) comme étant une URL différente, ayant son entrée propre dans l’historique des pages visitées. En même temps, un changement d’ancre ne recharge pas la page.

La classe History de GWT

En GWT, on peut être notifié par un système d’événement d’un changement d’ancre (et donc sans que la page ne soit rechargée) et connaître le nom de l’ancre. Ainsi, on peut exécuter du code et afficher telle ou telle vue en fonction de l’ancre actuelle. La classe History dans GWT permet cela. Et GWT propose une technique très efficace pour gérer ces changements dans l’interface en fonction de l’URL

Activity et Place

GWT part du principe suivant  : à une URL correspond un affichage de l’application. Cet état (visuel) de l’application qui dépend de l’URL s’appelle une Place.

A cette Place, on associe généralement une Activity, c’est à dire une fonctionnalité de l’application.

Cette Activity va alors exécuter le code qu’il faut pour placer l’interface dans l’état voulue par l’URL.

Pour résumer :

  1. de l’URL (ancre, encore appelé history token), on déduit une Place via un PlaceHistoryMapper,
  2. de cette Place, on déduit une Activity via un ActivityMapper.

Dans la pratique, cela se traduit se cette manière-là.

  • une classe par Place (ici : EditPlace et ListPlace),
  • une classe par Activity (ici : EditActivity et ListActivity),
  • un ActivityMapper (ici AppActivityMapper),
  • un PlaceHistoryMapper (ici AppPlaceHistoryMapper),
  • un point d’entrée (ici Index),
  • une Factory (ici ClientFactory) pour quelques objets dont on a souvent besoin.

Dans notre point d’entrée (Index.java)

// Nous avons besoin d'un panneau dans lequel vont s'afficher les différentes
// vues de l'application.
// Ici, ce sera la page entière, mais on pourrait n'avoir qu'une partie
// centrale par exemple, avec des menus globaux autour qui seraient toujours
// là.
SimplePanel rootPanel = new SimplePanel();
RootLayoutPanel.get().add(rootPanel);
 
// Le bus où tous les événements "métiers" de l'application seront déclenchés.
EventBus eventBus = ClientFactory.INSTANCE.getEventBus();
 
// Un peu de plomberie...
PlaceController placeController = ClientFactory.INSTANCE.getPlaceController();
ActivityManager activityManager = new ActivityManager(
   new AppActivityMapper(), eventBus
);
activityManager.setDisplay(rootPanel);
 
AppPlaceHistoryMapper historyMapper = GWT.create(AppPlaceHistoryMapper.class);
PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper);
// Place par défaut si rien n'est spécifié dans l'URL.
ListPlace defaultPlace = new ListPlace();
historyHandler.register(placeController, eventBus, defaultPlace);
 
// On déclenche tout ça !
historyHandler.handleCurrentHistory();

Ce qu’il est important de retenir ici :

  • Il est obligatoire d’avoir un seul conteneur qui sera la destination des différentes vues de l’application.
  • Ces initialisations sont certes un peu fastidieuses, mais elles peuvent être copiées/collées d’un projet à un autre (ou mutualisées, pourquoi pas, dans la ClientFactory).
  • Le déclenchement réalisé sur la dernière ligne n’est pas automatique : ne l’oubliez pas !
  • AppPlaceHistoryMapper est instancié via un defered binding (GWT.create()).

AppPlaceHistoryMapper :

package com.greenivory.gwt.tutorial.client;
 
import com.google.gwt.place.shared.PlaceHistoryMapper;
import com.google.gwt.place.shared.WithTokenizers;
 
@WithTokenizers( {
	EditPlace.Tokenizer.class,
	ListPlace.Tokenizer.class,
} )
public interface AppPlaceHistoryMapper extends PlaceHistoryMapper {
}

Ce qu’il est important de retenir ici :

  • Il suffit de lister les différentes Place (en fait, leur Tokenizer) dans l’annotation @WithTokenizers.

AppActivityMapper :

package com.greenivory.gwt.tutorial.client;
 
import com.google.gwt.activity.shared.Activity;
import com.google.gwt.activity.shared.ActivityMapper;
import com.google.gwt.place.shared.Place;
 
public class AppActivityMapper implements ActivityMapper {
 
    @Override
    public Activity getActivity(Place place) {
 
        if (place instanceof ListPlace) {
            return new ListActivity((ListPlace) place);
        }
 
        if (place instanceof EditPlace) {
            return new EditActivity((EditPlace) place);
        }
 
        return null;
    }
 
}

Ce qu’il est important de retenir ici :

  • A chaque Place, son Activity !

ClientFactory :

package com.greenivory.gwt.tutorial.client;
 
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.place.shared.PlaceController;
 
public class ClientFactory {
 
	private EventBus eventBus;
	private PlaceController placeController;
 
	public static final ClientFactory INSTANCE = new ClientFactory();
 
	protected ClientFactory() {
		eventBus = new SimpleEventBus();
		placeController = new PlaceController(eventBus);
	}
 
	public EventBus getEventBus() {
		return eventBus;
	}
 
	public PlaceController getPlaceController() {
		return placeController;
	}
}

Ce qu’il est important de retenir ici :

  • Il est impératif d’utiliser toujours les mêmes instances du PlaceController et du EventBus dans toute l’application. La ClientFactory (qui est un singleton) est donc une bonne pratique pour les contenir.

ListPlace :

package com.greenivory.gwt.tutorial.client;
 
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceTokenizer;
import com.google.gwt.place.shared.Prefix;
 
/**
 * Les URLs sont du type : http://server/index.html#ancre:token.
 * 'ancre' sert à déterminer la Place à utiliser.
 * 'token' sert à transmettre des paramètres à la Place.
 * Ce token peut être vide, mais le double-point est obligatoire.
 */
public class ListPlace extends Place {
 
	public ListPlace() {
        super();
    }
 
    @Prefix("list") // Ancre utilisée pour identifier cette Place.
    public static class Tokenizer implements PlaceTokenizer {
 
        @Override
        public String getToken(ListPlace place) {
        	// Retourner le token en fonction des paramètres de la place.
        	// Ici, jamais de paramètre, donc toujours chaîne vide
        	// (mais jamais null !).
        	return "";
        }
 
        @Override
        public ListPlace getPlace(String token) {
        	// En fonction du 'token' (derrière le double-point
        	// après l'ancre), instancier la Place.
        	// Ici, on ne gère pas de paramètres, donc on instancie
        	// toujours une ListPlace tout simple.
        	return new ListPlace();
        }
 
    }
}

ListActivity :

package com.greenivory.gwt.tutorial.client;
 
import com.google.gwt.activity.shared.Activity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.HTML;
 
public class ListActivity implements Activity {
 
	/**
	 * @param place
	 */
	public ListActivity(Place place) {
	}
 
	@Override
	public String mayStop() {
		// Retourner null pour autoriser l'arrêt de l'Activity.
		// Retourner une chaîne non-nulle pour demander à
		// l'utilisateur si l'Activity doit être stoppée ou non.
		return null;
	}
 
	/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#onCancel()
	 */
	@Override
	public void onCancel() {
		// Exécutée quand l'Activity n'est pas démarrée.
	}
 
	/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#onStop()
	 */
	@Override
	public void onStop() {
		// Exécutée quand l'Activity est arrêtée.
	}
 
	/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#start()
	 */
	@Override
	public void start(AcceptsOneWidget panel, EventBus eventBus) {
		// Code de l'Activity.
		panel.setWidget(new HTML(
		"Liste d'éléments | &lt;a href='#edit:1'&gt;Editer id=1&lt;/a&gt; | &lt;a href='#edit:3'&gt;Editer id=3&lt;/a&gt;"
		));
	}
 
}

Ce qu’il est important de retenir ici :

  • La méthode start() est indéniablement la plus importante, mais les autres sont très pratiques pour contrôler la navigation : l’utilisateur peut-il arrêter cette Activity (méthode mayStop()) ?

EditPlace :

package com.greenivory.gwt.tutorial.client;
 
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceTokenizer;
import com.google.gwt.place.shared.Prefix;
 
/**
 * Les URLs sont du type : http://server/index.html#ancre:token.
 * 'ancre' sert à déterminer la Place à utiliser.
 * 'token' sert à transmettre des paramètres à la Place. Peut être vide, mais le double-point est obligatoire.
 */
public class EditPlace extends Place {
 
	private int id;
 
	public EditPlace(int id) {
        super();
        this.id = id;
    }
 
	public final int getId() {
		return id;
	}
 
    @Prefix("edit") // Ancre utilisée pour identifier cette Place.
    public static class Tokenizer implements PlaceTokenizer {
 
        @Override
        public String getToken(EditPlace place) {
        	// Retourner le token en fonction des paramètres de la place.
        	// Ici, on s'attend à avoir l'ID en paramètre, donc on retourne une chaîne contenant l'ID de la Place.
        	return String.valueOf(place.getId());
        }
 
        @Override
        public EditPlace getPlace(String token) {
        	// En fonction du 'token' (derrière le double-point après l'ancre), instancier la Place.
        	// Ici, le token contient l'ID de l'élément à éditer : nous n'avons qu'à le transformer en entier...
        	try {
        		return new EditPlace(Integer.parseInt(token));
        	} catch (NumberFormatException e) {
        		return new EditPlace(-1);
        	}
        }
 
    }
}

Ce qu’il est important de retenir ici :

  • Il est possible de passer autant de paramètres qu’on le souhaite dans le token, pourvu qu’on le parse correctement.
  • Vous êtes libres de créer tous les paramètres nécessaires dans la Place.
  • Ne prenez pas à la légère la méthode getToken() : il est important qu’elle retourne le token qui permet de reconstruire une Place identique (avec les mêmes paramètres). getToken() doit être, en quelque sorte, le miroir de getPlace().

EditActivity :

package com.greenivory.gwt.tutorial.client;
 
import com.google.gwt.activity.shared.Activity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.HTML;
 
public class EditActivity implements Activity {
 
	private EditPlace place;
 
	/**
	 * @param place
	 */
	public EditActivity(EditPlace place) {
		this.place = place;
	}
 
	@Override
	public String mayStop() {
		// Retourner null pour autoriser l'arrêt de l'Activity.
		// Retourner une chaîne non-nulle pour demander à l'utilisateur si l'Activity doit être stoppée ou non.
		return null;
	}
 
	/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#onCancel()
	 */
	@Override
	public void onCancel() {
		// Exécutée quand l'Activity n'est pas démarrée.
	}
 
	/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#onStop()
	 */
	@Override
	public void onStop() {
		// Exécutée quand l'Activity est arrêtée.
	}
 
	/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#start(com.google.gwt.user.client.ui.AcceptsOneWidget, com.google.gwt.event.shared.EventBus)
	 */
	@Override
	public void start(AcceptsOneWidget panel, EventBus eventBus) {
		// Code de l'Activity.
		if (place.getId() == -1) {
			panel.setWidget(new HTML("<strong>Paramètre incorrect dans l'URL.</strong>"));
		} else {
			panel.setWidget(new HTML("Edition de l'élement " + place.getId()));
		}
	}
 
}

Ce qu’il est important de retenir ici :

  • Il est intéressant d’avoir accès à la Place pour en récupérer des informations (paramètres issus du token dans l’URL).

Une fois que tout est en place, changer de vue est un véritable jeu d’enfant ! Il y a deux possibilités :

  1. Dans un lien hypertexte, mettre l’URL de la Place vers laquelle on souhaite aller (attention au double-point derrière l’ancre, obligatoire, et souvent source de perte de temps).
    Par exemple #list: pour se rendre sur la liste des éléments.
    Ou #edit:3 pour se rendre sur la EditPlace pour éditer l’élément qui a l’ID 3.
  2. Dans du code GWT avec (par exemple) :
    ClientFactory.INSTANCE.getPlaceController().goTo(new EditPlace(47));

Dans un prochain article, nous étudierons comment utiliser le pattern MVP pour construire des UI propres et éviter de faire des vues à rallonge…

Jean Georges Perrin, CEO de GreenIvory

Jean Georges Perrin, fondateur de GreenIvory, envoie une lettre à ses clients, ses partenaires et amis. Vous pouvez le lire directement sur notre site web global. Quatre années de présence active en Alsace et en Europe, La société qui croit que « l’information doit être vécue » se porte bien et promet d’autres surprises en 2012… et avant…

A lire sur le site de GreenIvory.

Le 13 septembre 2011 a eu lieu l’inauguration du télécentre de Reichstett, au nord de Strasbourg. Il s’agit du premier télécentre expérimental du maillage Alsace ; il se situe 4 rue de l’Artisanat à Reichstett.
Alsace20 vous propose de revenir sur cet événement au travers de la vidéo ci-dessous.
Pour tous renseignements au sujet de ce télécentre et plus généralement du télétravail en Alsace, rendez-vous sur http://www.bureau-mobile.fr/.


Un télécentre pour travailler loin de chez soi! par Alsace20

VoiceObserver™

Ne laissez plus votre marque aux autres.
VoiceObserver™ est désormais un produit mature et quitte son statut de bêta. Nous y avons ajouté une nouvelle option fantastique : VoiceObserver™ remonte désormais dans le temps pour analyser la réputation en ligne. Vous voulez savoir combien et à quelle distance? Découvrez tout cela sur notre blog.

N’oubliez pas que VoiceObserver™ est vraiment adapté pour le benchmarking des marques. Alors n’oubliez pas d’ajouter vos concurrents « favoris » lorsque vous démarrez (ou modifiez) une analyse.

Découvrez VoiceObserver™ : http://VoiceObserver.com.

OnliGence™

L’info à votre mesure.
Imaginez… Un espace personnel, rien qu’à vous, qui vous présente uniquement l’actualité qui vous intéresse. Imaginez ce même espace vous faisant découvrir de nouvelles sources d’information… Eh bien, cet espace, ne l’imaginez plus : utilisez-le !

OnliGence™ est un excellent outil pour aider à lutter contre la surcharge d’information (l’infobésité) en classant automatiquement les nouvelles qui sont significatives pour vous. Aujourd’hui, OnliGence™ vous laisse découvrir plus de 280 thèmes et grâce à la version Premium, vous pouvez en afficher jusqu’à 20 en cinq colonnes à la une…

Découvrez OnliGence™ : http://OnliGence.com.

Cette semaine je profite de la Friday Update de VoiceObserver pour annoncer que le blog est enfin en ligne. Sur ce blog, vous retrouverez des articles sur les différentes évolutions du produit, les dernières nouveautés, des trucs et astuces, ou encore des exemples de projets. Les futures Friday Update concernant VoiceObserver seront aussi disponibles sur le blog. Le blog est disponible en français a l’adresse suivante : http://blog-fr.voiceobserver.com/ et en anglais à cette adresse : http://blog-en.voiceobserver.com/
Ce blog vous permettra aussi d’échanger des informations entre utilisateurs ainsi que de laisser vos avis sur le produit et ses fonctionnalités.