Archive for the 'java' Category

Responsabilité et atomicité des fonctions

Le projet sur lequel je travaille comporte des problèmes d’architecture que j’ai déjà évoqué dans mon billet précédent. Aujourd’hui, je souhaite aborder un autre problème de conception, qui concerne la répartition des responsabilités dans une classe.

Craig Larman nous conseille de respecter le principe de forte cohésion lorsqu’on défini les responsabilités que doit implémenter une classe. A une échelle inférieure, une méthode doit également respecter une certaine cohésion.

Pour être concret prenons l’exemple d’une méthode qui s’appellerait isValide() et supposons que l’implémentation de cette méthode nécessite d’effectuer une itération sur une liste. La tentation est de profiter du parcours de cette liste pour effectuer des traitements annexes « à la volée », ce qui évite de parcourir la liste une deuxième fois. Dans notre cas, le contrat annoncé par la méthode isValide() consiste fournir la réponse à une question. Pour respecter la cohérence de la fonction, celle-ci doit se contenter strictement d’y répondre et rien d’autre. Tout traitement annexe vient polluer la méthode et rend son utilité moins évidente.

Le problème qu’on peut rencontrer est que cela peut aboutir à une duplication de code. Pour reprendre l’exemple d’une fonction qui implémente une itération sur une liste, on peut se retrouver à implémenter cette itération dans plusieurs méthodes pour respecter l’unitarité de chacune d’elle. Si cela pose des problèmes rédhibitoires de performance, la solution est de n’avoir qu’une seule itération et d’implémenter le pattern Observer pour effectuer plusieurs traitements sur les éléments de la liste.

La cohérence d’une fonction rend son utilité plus claire ce qui facilite la maintenance du code.

La gestion des dates en Java

Je travaille actuellement sur un projet dans lequel nous avons besoin de manipuler des dates. Le projet est assez ancien, il date de plus de quatre ans, et à l’évidence, ceux qui ont écrit cette appli ne maîtrisaient pas très bien la programmation orientée objet. Et comme dans le même temps, très peu de documentation a été rédigée et que le projet a changé de domaine, je me retrouve tout seul à essayer de décrypter des lignes de code absconses et indigestes.

Je souhaite donc vous faire profiter d’un petit retour d’expérience afin d’améliorer la gestion des dates dans vos projets Java.

Petit rappel, il existe deux classes qui permettent de représenter une date dans l’api standard. Il s’agit de Calendar et Date, toutes deux dans le package java.util. Je ne traite pas ici du package java.sql.

Lorsque vous avez besoin de représenter une date en attribut d’une classe, je recommande l’utilisation de Date plutôt que Calendar. En effet, Date est un objet immuable (ou presque), il garanti qu’il ne sera pas modifié par mégarde et élimine les problèmes d’accès concurrent en cas de programmation multithread :

public class Personne {
    public final String nom, prenom;
    public final Date dateDeNaissance;
}

Faites attention lorsque vous initialisez une Date. Si vous utilisez le constructeur par défaut, la date sera initialisée avec pour valeur le nombre de milliseconde depuis le 1er janvier 1970. Le problème est que lorsque vous récupérez une deuxième Date par défaut et que vous les comparez toutes les deux, bien que ces deux dates correspondent au même jour calendaire, la comparaison échouera car la valeur en milliseconde sera différente.

Je recommande donc l’écriture d’une classe d’utilitaire qui permettra de manipuler les dates en adoptant une approche fonctionnelle :

public class CalendarUtil {
    private static final Calendar calendar = Calendar.getInstance();

    public static Date getDate(int jour, int mois, int année) {
    }
    public static Date getDate() {
        //retourne une date correspondant à la date courante (aujourd'hui)
    }
    public static Date incrementer(Date date, int jours) {
    }
    public static boolean equals(Date date1, Date date2) {
        //indique si deux dates correspondent au même jour calendaire
        //sans tenir compte des heures, minutes, secondes
    }
    public static int difference(Date date1, Date date2) {
        //retourne la différence en nombre de jours
    }
    public static boolean isEcheanceEchue(Date date, Periodicite period) {
    }
    public static String format(Date date, String pattern) {
    }
    [...]
}

Comme vous l’aurez constaté, cette classe d’utilitaire ne prend que des Date en paramètre. C’est en effet ma troisième recommandation et sans doute la plus importante. L’usage de Calendar doit être réservé aux calculs sur les dates, et donc être circonscrit à la classe CalendarUtil.

Je ne traite pas de la question des fuseaux et des locales, mais je recommande là encore une approche fonctionnelle

Par ailleurs, les plus perspicaces d’entre vous aurons remarqué que la méthode incrémenter() de CalendarUtil peut entrainer une conflit de signature. C’est le cas si l’on a besoin d’ajouter des mois ou des années à une date.

Dans ce cas, je recommande de suivre les préconisations de Stephan Schmidt :

public static Date incrementer(Date date, NbJours jours) {
}
public static Date incrementer(Date date, NbMois mois) {
}
public static Date incrementer(Date date, NbAnnees annees) {
}
public class NbJours {
    public final int value;
    public Jour(int value) {
        this.value = value;
    }
}
[...]

Ces recommandations, si elles sont suivies à la lettre, vous éviterons bien des soucis tel que je peux en rencontrer actuellement avec mon vieux projet. Dernier conseil qui va de soit, vous devrez évidemment tester unitairement chaque méthode de CalendarUtil.

Java est présent sur 99.9% des PC en entreprise

Selon une étude Forrester mentionnée sur Silicon.fr, le logiciel Java (JRE) est présent sur 99.9 % des PC en entreprise, devant le logiciel Flash (99%).

Un framework Swing

J’ai développé un framework Swing que j’ai appelé Swinger et qui permet de décrire une application de bureau avec un simple fichier XML :

<j:frame width="600" height="400" addWindowListener="actions.ActionQuitter" x="50" y="50">
	<j:menubar>
		<j:menu text="Fichier">
			<j:menuitem text="Quitter" addActionListener="actions.ActionQuitter"/>
		</j:menu>
	</j:menubar>
	<j:panel width="600" height="400">
		<j:textarea text="Hello !" width="300" height="200"/>
	</j:panel>
</j:frame>

Je dois avouer que je suis plutôt fier de mon bébé. Il est encore très incomplet car cela ne fait que trois jours que je travaille dessus, mais j’espère qu’il est promit à un bel avenir. J’ai écrit un KickStart sur le wiki du projet. Si vous avez des questions, n’hésitez pas à les poser dans l’onglet « Issues ».

Créer une application Facebook en Java

[EDIT]

Facebook abandonne le langage FBML. Dorénavant, toutes les applications devront être écrites selon les standards du web (HTML/CSS/JavaScript) et être intégrées à Facebook grâce aux iFrames. Ce tutoriel est donc devenu en grande partie obsolète.

[/EDIT]

Je vous propose un tutoriel pour créer votre première application Facebook. Il existe deux APIs standards, l’une en PHP, l’autre en Java. Nous allons étudier la seconde. Notre application s’appellera yafba (Yet Another Facebook Application).

Nota : Certaines lignes de code sont trop longues et ne s’affichent pas entièrement. Dans ce cas, faites un copier-coller dans un éditeur de texte.

Prérequis

Vous devez posséder un compte sur Facebook et ajouter l’application developers. Cette application va vous permettre d’obtenir une clé d’API pour votre application et vous permettre d’accéder à la documentation en ligne.

Vous devez également avoir un hébergement Java. En effet, bien que les utilisateurs accédent à votre application par l’intermédiaire de Facebook, vous hébergez vous-même l’application et les données que vous recueillez. Ce qui est important, c’est que le serveur qui héberge votre application doit être accessible publiquement par une URL. Il n’est pas nécessaire d’acquérir un nom de domaine, vous pouvez utiliser l’URL fournie par votre hébergeur.

L’environnement de développement

Vous devez télécharger l’API Facebook. Celle-ci est disponible via l’application developers :

L’archive contient le code source de la librairie à partir duquel vous pourrez générer la javadoc. Vous trouverez également la librairie compilée sous la forme d’une archive facebook.jar que vous devez importer dans votre projet.

Notez qu’il n’est pas possible de tester une application Facebook en localhost. Pour être testée, l’application doit être déployée sur le serveur que vous avez déclaré dans l’adresse de callback. Il existe néanmoins un émulateur accessible en ligne qui permet de tester son code FBML ou de tester l’API Facebook.

L’architecture

Nous n’aborderons pas la structure d’une application Facebook en détail, celle-ci est constituée de plusieurs composants dont la plupart sont générés automatiquement par les serveurs de Facebook. Nous nous intéresserons uniquement à la génération de la page d’accueil.

Pour faire fonctionner notre application, nous utiliserons un simple conteneur de Servlet, par exemple Tomcat. L’application reposera sur les Servlets et les JSPs. Les Servlets auront la responsabilité d’extraire les informations de l’API Facebook, et les JSPs serviront à générer la couche présentation au format FBML (FaceBook Markup Langage). Nous utiliserons accessoirement la librairie JSTL.

Référencement de l’application sur Facebook

Avant de développer notre application, nous allons commencer par la référencer sur Facebook. Pour cela, vous devez demander une clé d’API par le biais de l’application developers.

Les informations importantes à fournir sont le nom de votre application et l’URL de callback. Cette dernière doit correspondre à l’URL de votre serveur suivi du répertoire dans lequel vous avez l’intention de placer votre application. Elle est de la forme http://serveur.com/yafba/.

Vous pouvez également définir une URL pour le canvas qui correspond au cadre de votre application. Celle-ci est de la forme http://apps.facebook.com/yafba/. Ainsi, lorsque votre serveur contient un fichier http://serveur.com/yafba/index.jsp, celui-ci est accessible à travers Facebook par l’url http://apps.facebook.com/yafba/index.jsp.

Demandez enfin à ce que votre application puisse être intégrée à Facebook, cela permettra aux utilisateurs de l’ajouter à leur profil sous la forme d’un widget. Vous verrez alors apparaître des options supplémentaires. Parmi celles-ci, l’URL Post-Add correspond à l’URL « frontale » vers laquelle sont dirigés les utilisateurs qui cliquent sur le lien de votre application.

Toutes ces opérations se font à partir de l’application developers.

Connexion

Maintenant que notre application est référencée sur Facebook et que notre environnement de développement est correctement configuré, nous allons commencer à coder.

Nous allons écrire une Servlet « test » qui traitera les requêtes en provenance de Facebook :

<servlet>
	<servlet-name>test</servlet-name>
	<servlet-class>fr.hadf.yafba.servlets.Test</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>test</servlet-name>
	<url-pattern>/test</url-pattern>
</servlet-mapping>

La classe centrale de l’API est FacebookRestClient. Il s’agit d’une classe abstraite qui est héritée par deux sous-classes qu’on choisi selon le protocole qu’on veut utiliser, XML ou Jason. Nous allons utiliser le protocole XML.

La première chose que nous faisons est d’extraire le champ « fb_sig_session_key » de la requête entrante. Si ce champ est vide, nous redirigeons l’utilisateur vers la page de login dont l’URL est construite avec la clé d’API. Lorsque l’utilisateur aura été authentifié, il sera à nouveau redirigé vers notre Servlet, mais cette fois avec un champ « fb_sig_session_key » renseigné :

private void connection(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException, FacebookException {
	String sessionKey = req.getParameter("fb_sig_session_key");
	if(sessionKey == null) {//on redirige l'utilisateur vers la page de login
		String url = "http://www.facebook.com/login.php?api_key="+api_key+"&v=1.0&canvas&next=test";
		res.getWriter().println("<fb:redirect url='"+url+"' />");
		return;
	}
	else {//l'utilisateur est maintenant authentifié
		FacebookXmlRestClient client = new FacebookXmlRestClient(api_key, secret, sessionKey);
		loginSuccessfull(client, req, res);
	}
}

Utilisation de l’API Facebook

Nous allons maintenant utiliser l’API Facebook pour extraire la liste des amis de l’utilisateur courant :

protected void loginSuccessfull(FacebookRestClient client, HttpServletRequest req, HttpServletResponse res)
throws IOException, FacebookException, ServletException {
	Document root = (Document)client.friends_get();
	NodeList list = root.getElementsByTagName("uid");
	ArrayList friends = new ArrayList();
	for(int i=0; i<list.getLength(); ++i) {
		String uid = list.item(i).getTextContent();
		friends.add(uid);
	}

	req.setAttribute("friends", friends);
	getServletContext().getRequestDispatcher("/test.jsp").forward(req, res);
}

Nous utilisons simplement la fonction FacebookRestClient.friends_get(). Cette méthode retourne un objet diffèrent selon qu’on utilise le protocole XML ou Jason. Dans notre cas, nous récupérons un objet de type org.w3c.dom.Document. Pour connaître le format de la réponse, il suffit d’interroger la console de test disponible sur Facebook :

<?xml version="1.0" encoding="UTF-8"?>
<friends_get_response 	xmlns="http://api.facebook.com/1.0/"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd"
	list="true">

	<uid>1</uid>
	<uid>2</uid>
	<uid>3</uid>

</friends_get_response>

Nous extrayons alors le champ uid et utilisons l’objet request pour passer la liste des valeurs à la JSP.

Nous n’utilisons pas cette fonction, mais sachez que l’API permet également d’interroger la base d’utilisateur de Facebook grâce au langage FQL :

Document root = (Document)client.fql_query("SELECT name FROM user WHERE uid=" + uid;

Couche présentation

Nous commençons par écrire une page index.jsp qui nous servira d’URL « frontale », celle déclarée en URL Post-Add. Elle sollicite l’utilisateur pour envoyer une série d’invitations à ses amis afin d’ajouter notre application à leur profil :

<%@ page language="java" pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<fb:fbml>
	<fb:request-form type="yafba"
		action="test"
		content="Je vous invite à ajouter l'application yafba">
		<fb:multi-friend-selector actiontext="Selectionnez les amis auxquels vous voulez adresser une invitation"/>
	</fb:request-form>
</fb:fbml>

Notre application est ensuite très simple, elle se contente d’afficher une liste d’amis (test.jsp). Rappelons que cette liste a été extraite à partir de la Servlet « test » qui est appelée après validation du formulaire d’invitation. Nous utilisons la librairie JSTL pour garder propre la couche présentation :

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<fb:fbml>
	<c:forEach items="${requestScope['friends']}" var="uid">
		<fb:name uid="${uid}"/><br>
	</c:forEach>
</fb:fbml>

Conclusion

Vous venez d’écrire votre première application Facebook. Elle est accessible à partir du cadre « My Application » dans l’application developers.

Il ne s’agit que d’une présentation très modeste de ce qu’il est possible de faire. Ce tutoriel vous a surtout permis de comprendre l’architecture d’une application Facebook. A vous maintenant d’explorer la documentation si vous voulez aller plus loin.

Bonne continuation 😉

Remerciements

Je remercie Michael Bagur pour son aide précieuse, en particulier pour la phase de connexion à l’API, et pour sa relecture.

Que pensez-vous des évolutions à venir du langage Java ?

Le site developpez.com organise des sondages au titre de Java User Group en vue de récolter l’opinion des developpeurs Java sur les évolutions futures du langage. Je recommande à tous les developpeurs confirmés d’y participer et de partager leur opinon sur le forum.

A retrospective of Java

Un billet qui date un peu, et en anglais, qui présente une petite rétrospective de Java.

http://www.readwriteweb.com/archives/java_a_retrospective.php