Bla bla blog

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

mercredi 2 juin 2010

FXG vs SVG

Le langage FXG (Flash Xml Graphics) permet via des primitives (rectangle, cercle, ligne...) de définir des formes (composants) statiques ou dynamiques directement utilisables à l'intérieur d'une application Flex par exemple.

Mais pourquoi avoir défini un nouveau langage, alors que le langage SVG, qui plus est un standard, aurait très bien fait l'affaire.

L'article suivant nous donne quelques explications.

mardi 13 avril 2010

Dossier Android dans Programmez

A noter l'excellent dossier consacré à Android dans le mensuel "Programmez". Plusieurs connaissances dont Olivier Penhoat y ont contribué.

Couverture Programmez sur Android

Bonne lecture !

jeudi 11 mars 2010

Propagation d'événements depuis une popup

En Flex (ActionScript), comme dans tous les langages compatibles EcmaScript, lorsqu'un événement est émis depuis un composant, il va être propager entre différents objets, en suivant trois phases : capture, target et bubbling.

Imaginons l'événement clic sur un bouton, durant la phase de capture cet événement va traverser tous les composants et conteneurs parents du bouton en commençant par l'objet application avant d'atteindre le composant émetteur de l'événement. La phase "target", est justement la phase au cours de laquelle l'événement a atteint son émetteur. Enfin la phase de "bubbling" à renvoyer l'événement vers l'objet application en lui faisant prendre le chemin inverse de la phase de capture. Vous trouverez un certain nombre d'exemple dans cet article de la livedoc d'Adobe.

Ce mécanisme est très pratique car il me permet de factoriser des comportements identiques entre différents composants. L'exemple classique est celui d'un conteneur avec différents composants sur lesquels on souhaite effectuer des opération de drag&drop, plutôt que d'implémenter ce comportement identique sur chaque composant, il sera codé au niveau du conteneur dans un listeneur (handler) abonné au bons types d'événements.

Et les popups alors ??

Les popups sont créées via PopupManager.createPopup() et s'intègrent de la manière suivante dans l'arbre des objets flex : Graph propagation popups

Du coup, on comprend en regardant ce graphique que les événements ne remontent pas vers l'objet application mais directement vers l'objet SystemManager. Pour avoir un comportement factorisé pour toutes les popups, voire pour l'application, il suffira d'effectuer l'abonnement directement sur l'objet SystemManager comme suit :

Application.application.systemManager.addEventListener(...)

mercredi 27 janvier 2010

Comment embarquer une police dans une application Flex

Ayant eu le problème récemment, je vous conseille cet excellent article en français sur le sujet.

Pour résumer, il suffit de demander le chargement du fichier .ttf à la compilation de votre application tout en lui associant un nom logique. Ce nom logique vous permettra de désigner votre nouvelle police lorsque vous souhaiterez l'associer à un composant via la propriété css fontFamilly par exemple.

<mx:Style>
        global {
            fontFamily: chollSanReg;
        }
        </mx:Style>
        <mx:Script>
                <![CDATA[
                        [Embed(source="assets/fonts/ChollSanReg.ttf", fontName="chollSanReg")]
                        private var _chollSanReg:Class;
                ]]>
        </mx:Script>

Il est très intéressant d'embarquer vos propres polices dans vos applications Flex, car mis à part le fait que swf final est un peut plus lourd, si vous effectuez des rotation sur votre composant le texte avec votre police continuera d'apparaître, les effets de transparence (alpha) fonctionnent sur les polices embarquées et vous obtenez une meilleure définition lorsque vous zoomez sur votre texte.

dimanche 10 janvier 2010

Une première approche de Catalyst

Suite à une présentation de Catalyst faite par Michael Chaize au mois de décembre, j'ai eu envie de creuser ce nouvel outil qui fera sa sortie au premier semestre 2010.

L'idée de cet outil est de faire la jonction entre les équipes web design équipées de Illustrator, Photoshop et autre Gimp (oops) et les développeurs plutôt orientés flex et les technologies côté serveur (Java, Php, Coldfusion, etc.).

Personnellement, je trouve que ce nouvel outil remplit pleinement sa tâche avec plusieurs workflows possibles:

  1. j'intègre les fichiers .psd ou .ai fournis par les web designer pour définir tous les composants de base (bouton, scroll, etc.) de mon application et leurs interactions, et ainsi présenter une véritable maquette à mon client. Bien entendu le flexeur pourra reprendre ce projet (.fxp) pour ajouter toutes les échanges avec le serveur ou certaines interactions plus poussées.
  2. je définis rapidement l'organisation et toutes les interactions clientes de mon application avec des composants "wireframe" (sans mise en forme). Le client valide ces interactions, les équipes de web design et de développement peuvent alors travailler en parallèle. L'intégration des composants mis en forme pourra se faire ultérieurement, lorsque les designers auront terminer la personnalisation des composants. L'intégration reste à tester sur de projet de grande ampleur, mais Adobe travaille sur la possibilité de gérer les versions et ainsi facilité intégrations et itérations... à suivre donc
  3. enfin la possibilité de se faire une bibliothèque de composants personnalisés directement intégrables dans un projet flex

Attention les composants définis dans Catalyst ne pourront être utilisé que dans Flex 4.

Pour me faire une petite idée, je suis parti d'une image de l'Iphone, mon objectif étant de parvenir à recréer les interactions rapidement.

Vous pouvez vous faire une idée du résultat à l'adresse suivante : Iphone catalyst

Mon retour est que cet outil en version Beta est très agréable à prendre en main, pour obtenir ce résultat, il m'a fallu 1 journée en ne connaissant rien au départ (et en devant produire le fichier psd ce qui est moin d'être évident pour moi). Le seul inconvénient est qu'il est un peu gourmand en mémoire pour le moment et que je ne suis pas parvenu a créer les mouvement de drag&drop pour faire défiler le menu de l'Iphone, mais c'est peut-être par méconnaissance de ma part... Pour info c'est d'ailleurs pour cette raison que j'ai ajouté une barre de défilement en 3 clics.

L'étape suivante de cette petite démo, consisterait à l'intégrer dans flash builder (ex flex builder) pour pouvoir générer le contenu du menu, et l'horloge du téléphone... peut-être dans un autre billet !

Meilleurs voeux 2010

Voeux 2010

jeudi 16 avril 2009

Zend_Db : Utilisation du mapping

Après avoir vu comment définir le mapping dans ce précédent article, nous allons voir comment utiliser les classes de ce mapping pour faire du CRUD (Create, Read, Update, Delete) sur nos tables.

Gestion des connexions

Attention Zend_Db_Table utilise l'interface PDO (présente de la version 5.1 de PHP) pour se connecter votre base de données, pensez donc à activer les extensions correspondantes dans le fichier php.in (ie php_pdo.dll et php_pdo_mysql.dll pour une base de données MySql).

Ensuite dans le code il suffit de paramétrer l'adaptateur qui permettra d'établir les connexion de la manière suivante :

    $params = array(
        'host'     => '127.0.0.1',
        'username' => 'root',
        'password' => 'MY_PASSWORD',
        'dbname'   => 'test'
    );
    
    $db = Zend_Db::factory('Pdo_Mysql', $params);
    Zend_Db_Table::setDefaultAdapter($db);

On voit que la méthode static setDefaultAdapter() permet d'enregistrer l'adapteur auprès de la classe Zend_Db_Table, ainsi les connexions/déconnexions seront établies à la demande par cette dernière.

Créations

Pour effectuer une insertion en base de données, il suffit d'instancier la classe mappée sur la table correspondante (la classe Topic pour la table Topics dans notre exemple), puis appeler la méthode createRow() héritée de la classe Zend_Db_Table

$topic = new Topic();
$topic = $topic->createRow();

Vient ensuite l'affectation des différents champs de la table. Ces affectations peuvent s'effectuer en simulant des appels aux attributs de l'objet $topic :

$topic->name=$name;
$topic->forum_id=$id;
$topic->save();

ou en passant un tableau de paramètre à la méthode createRow

$data=array("title"=>$title,"topic_id"=>$id);
$post = $post->createRow($data);
$post->save();

Sans oublier la sauvegarde pour que les modifications soient commitées.

Sélections

Pour les sélections le mécanisme est exactement le même, c'est à dire que l'on commence par instancier la classe correspondant au nom de la table que l'on veut interroger avant d'utiliser les méthodes suivantes :

  • find() pour faire une recherche en filtrant sur la clé primaire
  • fetchAll() pour récupérer plusieurs résultats (RowSet) en ayant la possibilité de filtrer via les paramètres de la méthode
  • fecth() identique au fetchAll() sauf qu'un seul enregistrement (Row) sera retourné
$forum = new Forum();
$all = $forum->fetchAll(); //FetchAll retourne un RowSet donc parcours
foreach($all as $item){
     echo "id:{$item->id}, name:{$item->name}";
}

On voit dans cet exemple qu'en présence d'un RowSet, il faudra le parcourir de manière à récupérer les enregistrement un à un, ce sont en fait des objets Row qui permettent la lecture des valeurs de l'enregistrement.

Pour aller plus loin, comme nous avons défini des relations entre nos table Forum <1_n> Topic <1_n> Post, il est possible d'utiliser ces relations lors d'une selection via les méthode findDependentRowSet("Topic") ou findTopic() pour récupérer tous les enregistrements référençant un Forum. Cette technique est très appréciable pour naviguer dans la structure d'une base de données relationnelle sans ce soucier du SQL et des jointures.

$forum = new Forum();
$forums = $forum->find($pk);
$forum = $forums->current();//on récupère un seul enregistrement forum
echo "FORUM id:{$forum->id}, name:{$forum->name}\n";
$topics = $forum->findDependentRowset("Topic"); //recherche de tous les topics relatifs
foreach($topics as $topic){
    echo "\t TOPIC id:{$topic->id}, name:{$topic->name}\n";
    $posts = $topic->findPost(); //recherche de tous les posts relatifs
    foreach($posts as $post){
                echo "\t\t POST id:{$post->id}, title:{$post->title}\n";
    }
}

Tous les sources de cette démo sont en pièce jointe, il vous faudra simplement créer une base de données "test" ainsi que les trois tables Forums, Topics et Posts. Bon courage et merci pour vos éventuels retours.

Zend_Db : Définition d'un mapping objet relationnel

Dans ZF (Zend Framework) le mapping objet relationnel a été défini via les design patterns "table data gateway" et "row data gateway" inventés par Martin Fowler. Ces patterns permettent d'accéder ou de manipuler le contenu de table via des objets, ici ces objets seront de simples wrapper de notre structure relationnelle, donc chaque table est associée à une classe qui sera définie par le développeur en respectant un certain nombre de règles (héritage, redéfinition, etc) que nous verrons ici.

Un exemple de modèle relationnel

Pour illustrer les possibilités offertes par ce framework, nous prendrons un exemple simple : le forum de discussion, dont le modèle relationnel simplifié serait le suivant :
Forum modele relationnel
Donc simplement trois tables, avec une clé primaire id auto incrémentée sur chaque table et des clés étrangères de posts vers topics et de topics vers forums.

Définition du mapping

En respectant les principes des patterns précités, nous obtenons donc trois classes qui héritent de la classe Zend_Db_Table (fournie par ZF)
Mapping forum definition

Personnalisation du mapping

Toutefois ce mapping ne fonctionnera qu'à condition que votre table porte exactement le même nom que votre classe et que la clé primaire soit le champ ID et qu'elle soit auto-incrémentée. Pour tout autre cas de figure il faudra redéfinir les attributs $_name, $_id et $_sequence dans votre classe. Ainsi pour la classe Topic, nous aurons le code suivant :

<?php
require_once("Zend/Db/Table.php");

class Topic extends Zend_Db_Table{
    
    protected $_primary="id"; //clé primaire 
    protected $_sequence=true; //true est la valeur par défaut, pour une clé primaire auto-incrémentée
                                              //false entraîne l'obligation pour le développeur de renseigner la valeur de sa clé
                                              //une chaîne de caractère, pour les PK de type séquence (uniquement sur certains type de SGBDR)
    protected $_name="topics"; //nom de la table correspondant à cette classe

}
?>

Définition des relations

Dans ZF, la définition des relations doit être faite dans chaque classe. Elle s'appuie sur les relations définies au niveau de la base de données, c'est à dire les clés étrangères. Cette définition est importante car elle permet de "naviguer" dans la grappe d'objets récupérée, par exemple récupérer tous les posts relatifs à un topic, ou à partir d'un post retrouver son topic.

Prenons l'exemple de la table TOPICS, chaque enregistrement dans cette table doit référencer via une clé étrangère une entrée dans la table FORUMS, tout comme les enregistrements dans la table POSTS doivent référencer les entrées dans la table TOPICS. Voyons comment matérialiser ces relations au niveau de la classe Topic :

<?php
require_once("Zend/Db/Table.php");

class Topic extends Zend_Db_Table{
   [...]  

   //$_refernceMap est un tableau associatif qui représente toutes les clés étrangères ou relations de la 
   //table TOPICS avec d'autre tables
   protected $_referenceMap=array("forumKey"=>array(                 //forumKey est l'identifiant de cette relation, utile pour requêter la structure objet lorsqu'il y a plusieurs relations
                                                     "columns"=>array("forum_id"),  //Nom de la colonne portant la clé étrangère
                                                     "refTableClass"=>"Forum",       //Nom de la table référencée
                                                     "refColumns"=>array("id")));     //Nom de la colonne référencée (PK)

  //Noms de toutes les tables qui ont des relations avec la table TOPICS  
  protected $_dependentTables=array("Post");

}
?>

Nous venons de voir comment définir un mapping objet relationnel avec le module Zend_Db de ZF. Pour aller plus loin je vous propose la documentation de ZF.

mercredi 15 avril 2009

Authentification BASIC sur serveur Apache

Une authentification BASIC est mise en place lorsque le serveur web demande à l'internaute de saisir un login et mot de passe dès qu'il souhaite accéder à une ressource protégée. Il est possible de mettre en place une telle authentification sur un serveur Apache, et c'est ce que nous allons voir.

Création des comptes utilisateurs

Via l'utilitaire htpasswd.exe fourni avec la distribution Apache, il est possible de définir les créances (credentials) des utilisateurs, c'est-à-dire leurs logins et mots de passe. Ces couples login, mot de passe seront stockés dans un fichier à définir. Voici les principales commandes à connaître :

  • htpasswd –c user.pass jcc

Création du fichier user.pass et création du compte jcc. Le prompt permettra faire une double saisie du mot de passe dans la foulée.

  • htpasswd –b user.pass jcc monpassword

Ajoût de l'utilisateur jcc / password dans le fichier user.pass

Sécuriser les ressources du serveur web

La mise en place d'une authentification BASIC se déclare au niveau du serveur Apache dans le fichier httpd.conf au niveau de la déclaration des répertoires virtuels comme suit :

<Directory "c:/MonRepertoire/">
    AuthType Basic
    AuthName Blablabla
    AuthUserFile C:/MonRepertoire/user.pass
    Require valid-user
    Satisfy All
 </Directory>

Cross-browser, la solution pour tailles et positionnements

Le cross-browsing est votre cheval de bataille depuis que vous vous êtes lancé dans l'aventure du web, voici la solution universelle pour gérer les tailles et positionnements de vos applications : http://users.telenet.be/kixx/

vendredi 13 mars 2009

Théorie de la [R]évolution

La théorie de l'évolution selon Darwin a du plomb dans l'aile, il s'agirait plutôt de la théorie de la révolution selon Copernic... celle qui dit qu'un astre retourne au même point d'où il était parti. Le dessin ci-dessous en apporte la démonstration :

Révolution

De là à penser que l'homme est un astre...

mardi 10 mars 2009

Réconciliation avec Linux (guide d'installation Debian)

Voilà bientôt dix ans que je n'avais pas installé une distribution Linux digne de ce nom, il faut dire que mes précédentes expériences étaient douloureuses... Ceci est désormais du passé grâce notamment à ce tutoriel très didactique que je voulais très simplement vous partager.

Ce guide décortique pour vous toutes les étapes pour une installation réussie, du partitionnement optimal à la cohabitation avec Windows. Personnellement j'ai vraiment apprécié. Je n'ai d'ailleurs pas pu résister une fois l'installation terminée, à l'envie d'écrire une petite classe Java sous vi, en me rappelant au bon souvenir des commandes de cet éditeur fantastique !

Me voici réconcilié avec les pingouins..

jeudi 19 février 2009

Créer ses annotations

Spécifiées dans la JSR175 et apparues avec Java 5.0, les annotations sont désormais omniprésentes dans la plate-forme JavaEE et ses nombreux frameworks associés. L'occasion de revenir sur les techniques permettant de créer ses propres annotations.

Introduction

Les annotations que nous introduisons dans notre code sont à destination d'un "environnement d'exécution" qui va utiliser ces annotations pour effectuer des traitements supplémentaires ou configurer les traitements qu'il a l'habitude de faire. Ainsi si on prend le compilateur java comme "environnement d'exécution", l'annotation @Override lui indiquera que la méthode annotée a été redéfinie, le compilateur se chargera de vérifier qu'il s'agit bien d'une redéfinition. Notons que cette information ne sera nécessaire qu'en phase de compilation. Pour l'annotation @Deprecated qui indique si une méthode ou une classe est dépréciée, ainsi placée avant une méthode ou avant un classe, cette annotation n'aura pas le même sens.

Définition d'une annotation

Nous venons de le voir une annotation peut avoir une certaine portée, l'annotation @Deprecated n'était nécessaire que pour la phase de compilation. Par ailleurs certaines annotations s'appliquent à des méthodes, d'autres à des classes, des classes d'un certains type, etc... voilà les deux aspects que nous aurons à configurer sur nos annotations, et cette configuration se fera via... des annotations (ou des meta-annotations si vous préférez)

Définition de la portée ou "Rétention"

Vos classes Java, dans lesquelles vous placez vos annotations, passent par 3 états : code source, bytecode et bytecode interprété et chargé par le classloader de votre JVM. La méta-annotation @Retention vous permet d'indiquer dans quel états vous souhaitez utiliser votre annotation. Pour vous faciliter la tâches ces 3 valeurs sont stockées dans l'enum RetentionPolicy (SOURCE, CLASS, RUNTIME). Si on prend l'exemple de l'annotation @override, elle aura comme sera définie comme suit :

@Retention(RetentionPolicy.SOURCE)

A contrario des spécifications 3.0 des EJB ou des Servlets, les nombreuses annotations utilisées, le seront en phase d'exécution car le serveur d'application dans lequel vous déploierez vos composants aura besoin de découvrir les configuration associée à chacun de ces composants (url-pattern, name, init-param, session, stateless, stataful, entity, etc...).

Prenons l'exemple d'une annotation @Auteur qui nous permettrez d'indiquer dans le code quel est l'auteur de ce dernier, voici comment nous définirions une telle annotation. Dans le fichier Auteur.java :

package com.jcc.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Auteur {

}

Notez que l'annotation est placée dans un package comme n'importe quel élément (classe, enum, interface) Java et que le mot clé @interface permet d'indiquer qu'il s'agit de la définition d'une annotation

Définition de la cible ou "Target"

La meta-annotation @Target permet de définir une contrainte sur le contexte d'utilisation de notre annotation : classe, méthode, constructeur, attribut, etc. Là encore toutes les valeurs possibles sont stockées dans l'enum ElementType :

  • TYPE – s'applique uniquement au type java spécifié (classe, interface, enum, annotation)
  • FIELD – pour les attributs static ou d'instance d'une classe
  • METHOD – s'applique aux méthodes
  • PARAMETER – pour les paramètres d'une méthode
  • CONSTRUCTOR – destiné aux constructeurs
  • LOCAL_VARIABLE – pour les variables locales d'une méthode
  • ANNOTATION_TYPE – pour les annotations dont le type est à précises
  • PACKAGE – s'applique à l'intégralité du package indiqué

Imaginons que nous souhaitions appliquer notre @Auteur aux méthodes et aux constructeurs, voici comment nous devrions définir notre annotation :

package com.jcc.annotations;

import java.lang.annotation.*;

@Target({ElementType.CONSTRUCTOR,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auteur {

}

passage de propriétés

Dernier point, il est généralement nécessaire de passer des paramètres à nos annotations. Dans notre cas, il s'agirait de passer le nom de l'auteur qui souhaite signer la méthode ou le constructeur qu'il vient d'écrire. Pour pouvoir passer de tels paramètres il faut les déclarer lors de la définition de l'annotation comme suit :

package com.jcc.annotations;

import java.lang.annotation.*;

@Target({ElementType.CONSTRUCTOR,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auteur {

        String nom();
        
}

Si vous souhaiter rendre ce paramètre optionnel, donnez lui une valeur par défaut comme indiqué dans l'exemple ci-dessous :

package com.jcc.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.CONSTRUCTOR,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auteur {

        String nom() default "Auteur par défaut";
        
}

Utilisation de l'annotation

Une fois cette annotation compilée vous pourrez l'utilisez directement avant vos déclaration de méthode ou de constructeur comme dans l'exemple :

public class ClasseDeTest {

        @Auteur
        public ClasseDeTest() {
        }
        
        @Auteur(nom="John Smith")
        public String toString() {
                return super.toString();
        }
}

Les informations sur l'auteur de cette méthode et de ce constructeur seront disponibles pour le compilateur, le classloader et la JVM, ainsi à l'exécution et via l'api d'introspection de Java il sera possible de retrouver l'auteur de cette méthode ou de ce constructeur.

Nouveautés servlet 3.0 (JSR 315) - Les annotations

Introduction

Cet article met l'accent sur la nouvelle série d'annotations introduites qui peuvent être utilisés par les développeurs plutôt que de mettre les données dans le fichier de configuration

Facilité de développement par Annotations

Les informations sur les composants Web tels que les Servlets, Servlet filtres sont mentionnées dans le descripteur de déploiement, qui est web.xml. A partir de Servlet 3.0, il est également possible de spécifier des méta-informations sur un élément (classe, interface), cette opération se fera via les annotations. Le fichier web.xml ne disparait pas pour autant. D'ailleurs les informations qu'il contient sont toujours prioritaires sur celles des annotations. Il est également possible d'activer ou pas la prise en charge des annotations par le conteneur via la balise <metadata-complete> directement placée sous la balise <web-app> du fichier web.xml. Cette balise attend les valeur "true" (le web.xml est complet, il se suffit à lui même) ou false (dans ce cas les annotations devraient être prises en compte)

Les annotations suivantes sont applicables à partir de spécifications Servlet 3.0,

    * @WebServlet 
    * @WebServletContextListener 
    * @ServletFilter 
    * @InitParam

Annotations WebServlet et InitParam

Dans cette section, nous allons voir l'utilisation de @WebServlet et @InitParam par un exemple.

package net.javabeat.servlet30.newfeatures;

import javax.servlet.annotation.InitParam;
import javax.servlet.annotation.WebServlet;

@WebServlet(
    name = "SimpleServlet", 
    urlPatterns = {"/simple"}, 
    initParams = {
        @InitParam(name = "param1", value = "value1"),
        @InitParam(name = "param2", value = "value2")}
)
public class SimpleServlet {

}


Dans cet exemple, nous avons créé une classe SimpleServlet qui n'hérite pas de HttpServlet, contrairement à ce que prévoit la spécification originale. En revanche, pour bénéficier de cette classe comme une classe Servlet, nous avons annoté en utilisant l'annotation @ WebServlet. Notez que le nom de la servlet est SimpleServlet comme spécifié par l'attribut name. L'attribut urlPatterns définit un ensemble de modèles url-qui peut être utilisé pour invoquer la Servlet. Voici le descripteur de déploiement équivalant :

<servlet>
    <servlet-name>SimpleServlet</servlet-name>
    <servlet-class>net.javabeat.servlet30.newfeatures.SimpleServlet</servlet-class>

        <init-param>
            <param-name>param1</param-name>
            <param-value>value1</param-value>
        </init-param>

        <init-param>
            <param-name>param2</param-name>
            <param-value>value2</param-value>
    </init-param>

</servlet>

<servlet-mapping>
    <url-pattern>/simple</url-pattern>
    <servlet-name>SimpleServlet</servlet-name>
</servlet-mapping>

Nouveautés servlet 3.0 (JSR 315) - Introduction

Après la révolution des EJB 3.0, les servlets leur emboitent le pas et passent à leur tour en version 3.0. Comme pour les EJB, la principale nouveauté correspond à une simplification de la spec avec des annotations à la place des fichiers descripteur de déploiement, mais ce n'est pas tout... Notez que cette spec n'est pas encore finalisée, certaines parties risquent de bouger encore un peu. Je me lance donc dans une suite d'articles consacrés à cette spécification et dans lesquels je compte successivement traiter :

  1. les annotations
  2. l'intégration des frameworks (struts, jsf, etc.)
  3. Les requêtes asynchrones

Notez que certains articles seront parfois inspirés d'autres post, voire de simple traduction, c'est pourquoi je tiens d'ores et déjà à indiquer les sources utilisées :

mardi 17 février 2009

JQuery à la sauce Zend

Dans sa version 1.7, ZF (Zend Framework) a vu pas mal de nouveautés, parmi lesquels il faut d'après moi relever les extensions :

  • Zend_AMF pour un support du protocole AMF d'Adobe. On peut ainsi imaginer un frontal Flex/AS/Flash avec un back-end PHP, c'était déjà le cas avant via HTTP ou les web services, l'intérêt du protocole AMF étant de permettre au serveur de mettre à jour les clients sans qu'ils ne l'aient sollicité.
  • ZendX_JQuery pour un support du célèbre framework AJAX qui est en train de supplanter tous ces concurrents. Pour vous faire une idée des widgets mis à votre disposition, et la manière d'utiliser cette extension je vous conseille cette démo

Pour le reste des nouveautés il s'agit surtout de mise à jour des librairies existantes, d'amélioration des perf pour le Zend_Loader et de la corrections de quelque 300 bugs.

Voici un post qui donne un peu plus de détail :

Zend Framework 1.7.0 is now available from the Zend Framework download site: http://framework.zend.com/download/latest

This release introduces many new components and features, including:

* Zend_Amf with support for AMF0 and AMF3 protocols * Dojo Toolkit 1.2.1 * Support for dijit editor available in the Dojo Toolkit * Zend_Service_Twitter * ZendX_JQuery in extras library * Metadata API in Zend_Cache * Google book search API in Zend_Gdata * Preliminary support for GData Protocol v2 in Zend_Gdata * Support for skip data processing in Zend_Search_Lucene * Support for Open Office XML documents in Zend_Search_Lucene indexer * Performance enhancements in Zend_Loader, Zend_Controller, and server components * Zend_Mail_Storage_Writable_Maildir enhancements for mail delivery * Zend_Tool in incubator * Zend_Text_Table for formatting table using characters * Zend_ProgressBar * Zend_Config_Writer * ZendX_Console_Unix_Process in the extras library * Zend_Db_Table_Select support for Zend_Paginator * Global parameters for routes * Using Chain-Routes for Hostname-Routes via Zend_Config * I18N improvements - Application wide locale for all classes - Data retrieving methods are now static - Additional cache handling methods in all I18N classes - Zend_Translate API simplified * File transfer enhancements - Support for file elements in subforms - Support for multifile elements - Support for MAX_FILES_SIZE in form - Support for breaking validation chain - Support for translation of failure ,messages - New IsCompressed, IsImage, ExcludeMimeType, ExcludeExtension validators - Support for FileInfo extension in MimeType validator * Zend_Db_Table_Select adapater for Zend_Paginator * Support for custom adapters in Zend_Paginator * More flexible handling of complex types in Zend_Soap

In addition, almost three hundred bugs have been fixed:

http://framework.zend.com/issues/sec...equestId=10903

The Zend Framework team would like to thank everyone who made this release possible. As always, our generous ZF community has provided countless new features, bug fixes, documentation translations, etc. We'd also like to thank Adobe Systems and Wade Arnold for contributing the new Zend_Amf component. A big thanks to PHP Belgium and everyone who participated in bug hunt day (http://www.bughuntday.org/) and/or the Zend Framework bug hunt week. Finally, we'd like to thank all of those whom we've forgotten to thank above. Once again, we're reminded that Zend Framework is about much more than code, it is about community. See y'all online.

,Wil

vendredi 13 février 2009

Installer Joomla en version française

Joomla est certainement un des CMS (Content Management System) les plus utilisé du moment. Nous allons simplement lister les tâches à réaliser pour l'installer correctement en local :

  1. Installer l'environnement Apache + PHP (suivre les consignes de cet article )
  2. Installer une base de données MySQL et la démarrer sous forme de démon mysql-d.exe
  3. Via un outil d'administration (personnellement j'utilise MySQL Control Center), se connecter sur la base de données, créer une nouvelle instance de base et noter tous les paramètres de connexion (login, pwd, nom de l'instance)
  4. Télécharger l'archive de Joomla et la décompresser dans un répertoire en local.
  5. Dans le fichier httpd.conf de Apache, créer un alias /joomla par exemple qui redirigera toutes les requêtes vers le répertoire dans lequel nous avons décompressé notre archive. Cette technique est indiquée dans cet autre article
  6. Vous allez désormais pouvoir vous lancer dans la configuration de votre site, pour cela il vous suffit de saisir l'adresse suivante http://localhost/joomla/index.php dans votre navigateur préféré. Le processus de création est correctement indiqué dans ce document.

Bon courage !

mercredi 11 février 2009

Mo-Du-La-Ri-Té, Modularité

Là où certains scandent le mot fraternité, d'autres plus proche du monde IT semblent adopter le mot modularité. Quand je pense que sur les bancs de l'école on nous disait alors que l'approche objet permettait la réutilisabilité, qu'on allait pouvoir travailler indépendamment sur des couches (modules) distinctes et réutilisables... En fait en prenant un peu de recule, en phase de développement effectivement nos packages nous permettent de correctement distinguer les couches d'accès au données, présentation, etc. En plus si on utilise des frameworks comme maven, la structure de notre projet fera clairement apparaître nos différents artefacts en vue du build. Mais force est de constater qu'une fois le build effectué, l'archive à déployer fera moins apparaître cette modularité. Prenons un EAR, certes il sera par exemple composé d'un war et d'un ou plusieurs JAR pour les couches de services et d'accès aux données, mais dans un tel découpage on retrouvera les classes métiers, les interfaces des façades, et toutes les classes communes aux différentes archives.

Java 7.0 et la modularité

Comme le fait remarquer Alex Moussine Pouchkine (Architecte Java chez Sun) : "le système de package de Java est obsolète et pose les mêmes problème que les DLL de Microsoft". La JSR 277 a donc vu le jour chez SUN pour remplacer le système d'archive actuel (jar, war et ear) et la première implémentation de cette JSR devrait voir le jour dans la prochaine version du JDK, soit Java 7.0. Issues de la spec, voici les réponses que devra apporter cette JSR 277 également appelée Java Module System (JMS rien à voir avec Java Messaging System) :

  1. Un nouveau format de distribution des classes java et ressources associées, ainsi qu'un nouveau format pour les métadonnées associées au module.
  2. Une spécification pour réaliser un référentiel de modules (exit les référentiels Maven ??)
  3. Les métadonnées indiqueront :
  • une description du contenu du module
  • les dépendances vis à vis d'autres modules en précisant les versions de ces derniers
  • l'ensemble des ressources (Java et autres) accessibles depuis d'autres modules

Je ne sais pas ce que vous en pensez, mais ça me rappelle étrangement la notion de bundle OSGi, comme les plugins Eclipse, dans lesquels on trouve exactement les mêmes notions. J'avoue partager le constat sur les limitations des archives d'un point de vue modularité, mais de là à définir un nouveau standard... serait-ce un choix politique plutôt que technique ? Pour aller plus loin, je vous conseille ce billet provenant de l'OSGi Alliance.

GlassFish et la modularité

Au delà de la prochaine version de Java, on parle également de la sortie prochaine de Java EE 6 et surtout du premier serveur d'application qui implémentera cette nouvelle mouture : GlassFish V3. Les atouts mis par Sun pour la nouvelle version de GlassFish sont : la modularité, l'extensibilité, la possibilité de déployer ou supprimer de nouveaux services "à chaud". Cette approche permettra de définir des profils d'utilisation de GlassFish et donc de supprimer certains services couteux (RMI, JMS, JNDI, EJB, WS, etc.), mais Sun nous indique qu'il sera possible de réinstaller ces services à tout moment et sans redémarrer le serveur d'application. Pour parvenir à ce résultat la plate-forme de GlassFish reposera sur... OSGi (?)

mardi 10 février 2009

Milestone 1 pour Eclipse 4

La fondation Eclipse vient de publier le premier milestone de la version 4 de sa plate-forme. Cette version promet de nombreux changements que vous pouvez découvrir à cette adresse.

La grande nouveauté vient de la définition de la structure des IHM (menu, perspectives, vues, etc...) qui sera désormais faite via EMF (Eclipse Metamodel Framework) et non plus directement en SWT. L'idée étant de tendre vers le RAD (Rapid Application Development) et donc qu'à partir d'une modélisation que tout le code SWT/JFace soit généré. La seconde grande nouveauté vient du support de CSS (Cascading StyleSheet) pour la mise en forme via des styles de la structure précédemment définie.

J'ai hâte de tester davantage ces deux points ainsi que la gestion des modèles de données à associer aux écrans ainsi définis. Nul doute que le projet est intéressant, j'admets tout de même avoir quelques craintes pour les projets RCP existants à migrer vers cette nouvelle mouture de la plate-forme Eclipse. Ces quelques tests à venir seront l'occasion d'un nouveau billet.

lundi 9 février 2009

Exemple : Tester une application avec SWTBot

Suite à la présentation qui a été faite de SWTBot, nous allons présenter dans cette article un exemple de test sur une application développée avec SWT. Nous avons choisi une application de Tchat avec deux tests à réaliser : s'assurer que les composants graphiques sont bien présents et qu'après l'envoi d'un message la zone de saisie est de nouveau vide. Chat swt

Classe de test

Définition

Les classes de tests dans SWTBot doivent hériter de SWTBotTestCase. Cette classe hérite elle-même de la classe TestCase de JUnit, ce qui prouve que SWTBot est une extension du framework JUnit. Cela signifie également que vous aurez la possibilité de redéfinir les méthode setUp() et tearDown() dans vos classes de test.

Démarrage de l'application

Pour plus de facilité, c'est la classe de test qui va démarrer notre application graphique dans un autre thread. Nous allons donc ajouter une partie static qui se chargera du lancement de l'application à tester au chargement de la classe de test.

static {
    startApplicationInAnotherThread();
}
private static void startApplicationInAnotherThread() {
    new Thread(new Runnable() {
        public void run() {
            new ChatView().main(new String[]{});
        }
    }).start();
                
    long endTime = System.currentTimeMillis() + 5000;
    while (System.currentTimeMillis() < endTime) { 
    try {
        Display display = SWTUtils.display();
        if (display != null)
            break;
    } catch (Exception e) { }
    }
}


On voit dans cet exemple que l'application ChatView est démarrée, puis on essaie de récupérer l'objet Display dans un boucle while pour s'assurer que l'application graphique a bien été démarrée avant de commencer l'exécution des tests


Ecriture des tests

Les méthodes de test doivent toutes être nommée testXXX(), Il s'agit d'une convention reprise de JUnit. Puis il s'agit de récupérer des références sur les objets graphiques de l'interface, cette opération se fait via l'attribut bot, qui est hérité de la classe SWTBotTestCase. Enfin les méthodes assertXXX() (comme dans Junit) nous permettrons de tester l'état de nos composants graphiques.
Voici un exemple qui permet de s'assurer que tous les composants graphiques de l'interface sont bien présents et actifs. Notez la manière de récupérer une référence sur l'objet graphique via bot.

public void testPresence() throws Exception{
    assertNotNull(bot.activeShell());
    assertEnabled(bot.text(""));
    assertEnabled(bot.button("Envoi"));
}


Ici un autre exemple qui permet de dérouler un scénario fonctionnel, l'envoi d'un message via l'IHM de tchat, et de s'assurer une fois le message envoyé que la zone de saisie est bien vide.

public void testEnvoi() throws Exception{
    SWTBotText txt = bot.text("");
    txt.setText("Bonjour à tous");
    bot.button("Envoi").click();
    assertEquals("", txt.getText());
}

Exécution du test

Dans Eclipse l'exécution du test sera identique à celle d'un test JUnit, c'est à dire via le menu run... Notez tout de même qu'en mode debug, les méthodes pour récupérer une référence sur un objet graphique ne fonctionnent pas, cela vient probablement de la gestion des threads (ce point reste à élucider). Dernière remarque, si vous écrivez plusieurs classe de tests, il serait bon de les regrouper dans une TestSuite de manière à ne démarrer qu'une seule fois l'application.
Tout le code est en pièce jointe.

- page 1 de 2