insideIT.fr : le blog des architectes IT de SFEIR

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

mardi 28 juin 2011

Code Retreat #1

Ce 24 juin, j'ai assisté à un code retreat, organisé par Jean-Laurent de Morlhon et Simon Caplette, chez Xebia.
Avant de m'inscrire, je n'en connaissais pas le principe. Je me réfère donc à la définition donnée par les organisateurs :
"Le principe est le suivant: sur la journée coder en binôme sur plusieurs sessions de 30-45 minutes chacune afin de résoudre un problème. A l’issue de chaque session on change de binôme et tout le code produit est effacé. Drastique mais efficace pour rester créatif. C’est aussi le lieu privilégié pour tester de nouvelles techniques et algorithmes."
C'est un concept de coding dojo que je n'avais essayé, d'où mon envie de tester.

Le temps que tout le monde soit là et installé, un traditionnel petit déjeuner nous attendait.
Avant de commencer, l'organisation de la journée nous est présenté :
- Le but n'est pas de finir, mais de faire ce que l'on peut
- Par recommmencement on finit par s'améliorer, on cherche à améliorer la façon de faire.
- Une session est composé de 40 min de développement en pair programming et 20 min de débriefing général.
- Ici c'est différent du boulot, on a le temps, inutile de rusher. Nous sommes ici pour apprendre, tester d'autres façons de faire, essayer un autre langage ou un autre ide, découvrir des plugins d'ide, ...
- Procéder par TDD et suivi les principes de YAGNI. Si ce sont des pratiques que l'on ne fait pas au quotidien dans notre travail, c'est justement l'occasion de s'y exercer
- Une session est composé d'une partie de développement de 40 min en pair programming, suivi de 10-15 min de retrospective globale.
- Une retrospective globale en fin de journée

Souvent le jeu de la vie est utilisé en code retreat, ici pour changer ce sera TicTacToe dont les spécification nous sont fournis en 6 règles :
1/ Une partie est finie lorsque tous les champs sont pris.
2/ Une partie est finie lorsque une colonne est prise par un joueur.
3/ Une partie est finie lorsque une ligne est prise par un joueur.
4/ Une partie est finie lorsque une diagonale est prise par un joueur.
5/ Un joueur peut jouer lorsque un champ n'est pas pris.
6/ Les joueurs jouent à tour de role jusqu'à ce que la partie soit finie.

Au total, sur la journée 5 sessions auront lieu.


Session 1


Au bilan de cette première session, certains remonte l'usage de plugins Eclipse :
- Pair Hero : duels en pair programming où chacun code à tour de role jusqu'à ce qu'un test échoue. Des points sont gagnés en fonction de refacto ou rapidité à faire passer le clavier.
- Infinitest : lance les tests unitaire à chaque enregistrement du code, économise ainsi des switch test/code.
Beaucoup prennent les régles dans l'ordre, mais est ce bien utile ?
Quant à l'implémentation, le plateau est codé sous diverse forme : tableau à 2 dimensions, chaine simple, ...


Session 2


Les noms de classes eux aussi sont variés : TicTacToe, Party, Board, ... tout comme les méthodes de fin : checOver, isOver(), ....
Des questions sur le moment où refactorer se posent. Le mieux est quand on veux, quand celà nous semble un moment logique, une étape. Et il ne faut pas oublier que la refacto concerne aussi bien, le code métier que les tests.
Quelques personnes pense qu'ils ont introduit la notion de joueur trop tôt, ils auraient pu refactorer lorsqu'ils en auraients eu besoine.
Profitant de l'occasion de pouvoir refactorer, certains ont changé leur design, parfois avec regret. Mais y trouve tous l'avantage du recommencement, qu'ils ne peuvent pas faire au boulot.


Session 3


Quelqu'uns trouvent un avantage dans l'implémentation de recherche interne, pour une raison de facilité de recherche interne.
Pour la part, après 2 sessions orientée sur la détection de fin de partie, mon code était plutôt orienté vers la le tour par tour des joueurs.
Une problématique courante remonte : placer le jeu dans un état précis pour tester par exemple des configuration de plateau. Une solution possible serait d'avoir une méthode d'initialisation.
Les animateurs remontent qu'ils entendent parler d'architecture, mais qu'il s'agit là d'une notion bien poussée, car la seule voulue, c'est un simple jeu.

Pause repas


Après toutes ces aventures de la matinée, nous avons le droit à un repas geek : pizza/coca !
Pour l'apres midi, pour ceux qui souhaitent, on monte le niveau avec des objectifs :
- No Mouse : souris interdite, uniquement clavier.
- 5 min par personne : on alterne le clavier toutes les 5 minutes.
- Tdd as if you meant it : Tdd encore plus poussé avec des régles comme coder son code métier dans la classe de test.

Session 4


Pour cette session, 2 groupes ont testé un autre langage :
- JavaScript (Mathilde Lemée et Eric Le Merdy) : Utilisation de JQuery, structure de données portée par la page. QUnit ne semble pas super pour tester du js.
- Ioke (David Gageot et moi même) : Je ne connaissais absolument pas ce langage, j'ai donc était volontaire pour le découvrir. C'est un langage entre lisp, ruby et smalltalk qui tourne aussi bien sur une VM java que .Net. Nos tests sont assez très lisible, au contraire du code. En effet, de refacto en refacto et par jeu, nous avons réduit de façon très importante le code en utilisant toute la puissance du langage. Si bien que notre code pour les régles lignes et colonnes tient en 3 lignes.
Ceux qui avaient l'objectif, Tdd as if you meant it sont satisfaits, par le fait d'avoir pu repousser le moment de décider où placer son code.

Session 5


Le groupe JS a poursuivi ce qu'il avait commencé et nous montre leur réalisation. Le js a permit de connecter facilement à une ihm html, la structure de données est directement dans le dom plutôt que dans des objets js.
David a continué en Ioke avec un autre volontaire pour découvrir le langage. De nouvelles refacto ont eu lieu, et le code pour tester les 4 ères régles tiennent sur environ 6 lignes.
Nos animateurs nous montrent un exemple de Tdd as if you meant qu'ils avaient réalisé. Le retardement du choix du placement du code a fait qu'ils ont eu une approche fonctionnelle, où le modèle est sans état.
Et pour finir, ils énumèrent quelques possibilité de challenge possible en code retreat : No loop, No If, ...
Invonlontairement, ces 2 challenges ont été vaincus par David et son code en Ioke.


Debriefing de la journée


Nous finissons la journée sur une rétrospective finale sur ce que nous avons appris et ce qui sera pratiqué au retour au travail. Dans le désordre :
- Découverte du tdd et voir quelle limite dans l'approche du code nécessaire à faire passer le test.
- Le tdd permet de penser plus au fonctionnel.
- Necessité de plus pousser le principe de code minimal afin d'affiner ses tests.
- Réticence à Infinitest vaincu. Pour des tests volumineux, il est paramétrable.
- Un autre langage qui faire penser différement.
- Pair Hero assez plaisant
- Parfois on pense avoir résolu de manière optimale un problème mais après avoir recommencé avec une autre personne, on se rend compte que non.
- Progression dans les tests car parfois quasiment pas de tests dans les projets au boulot.
- Nouvelle vision à chaque fois.
- Du test fait mais pas tdd, ce qui fait une nouvel outil à utiliser.
- Il peut être utile d'avoir une phase de réflexion avant de se lancer dans les tests.
- Des discussions intéressantes.
- Passer plus de temps sur la refacto.




Un autre Code Retreat aura lieu le 2 juillet, avec Oana Juncu de Sfeir comme animatrice.
A l'heure actuelle, il reste quelques places dépéchez si vous être intéressés.

jeudi 23 juin 2011

La marmite des Duchess

La 1ère édition de la Marmite des Duchess a eu le 7 juin dernier. Nom de code "Crumble".
Ce nouvel évènement, proposait 2 sessions en parallèle, le choix se faisait à l'inscription :
- Atelier Mockito, animé par Mathilde Lemée et David Gageot. (limité à 20 places)
- Open Space Technologique. (limité à 40 places)
Doit on y voir l'anologie du crumble dans ce découpage ? Je ne saurais répondre à cette question.

Au total, une trentaine de personnes (dont 6 Sfeirien(ne)s) étaient présentes pour une durée d'un peu plus de 2 heures.

Atelier Mockito





C'est la partie à laquelle j'ai assisté.
Cet atelier était basé sur le code de tudu-list. Le but était de, en peer programming, compléter des tests et de les faire passer au vert. Pour palier aux différentes connaissances et niveaux des participants, les tests étaient répartis en 3 niveaux de difficulté.
Pour ma part, connaissant un peu Mockito, j'ai affronté le niveau 2. Nos animateurs étaient bien sûr présent pour nos différentes questions sur la façon de développer/organiser nos tests aussi bien sur Mockito mais aussi sur FestAssert.
Ces exercices permettent d'avoir quelques bases sur Mockito en découvrant sa syntaxe et ses particularités mais aussi si nous sommes rigoureux de se familiariser avec le formalisme BDD,  conseillé pour bien se concentrer sur une seule chose à tester par méthode de test.

Si vous souhaitez tenter le défi, le code à compléter est ici et la solution .

Open Space Technologie




D'après ce que j'en ai compris, un open space technologie est assez semblable à un bar camp, mis à part qu'il n'y a pas de sessions parallèles.
N'ayant pas de don d'ubiquité, je n'étais pas présent à cette partie. Mais heureusement, mon collègue Clément Griffoin avait pris des notes.


Différents sujets ont étés abordés dont :
- Women in java
- ForPlay où Pierre-Yves Ricau fera une démonstration de sa réalisation
- Déploiement continu
- Stubs vs Mock
- TDD/DDD/BDD


Vous pourrez retrouver plus d'informations ce qui s'est dit dans cette partie sur le blog des Duchess.

Et pour finir, c'est un autour d'un repas que les derniers motivés se sont retrouvés.


Merci et félicitations pour cette première édition ! Et vivement la suite à la rentrée.

Des photos de cet article ainsi que toutes les photos la soirées sont disponible sur l'espace Flickr de Duchess France

Du Protobuf dans mon Jersey

J'avais déjà parlé, dans de précédents articles, de la génération de xml et de json avec Jersey. Et si maintenant, on s'amusait à générer du protobuf ?
On parle de protobuf pour Protocol Buffers, une techno Google pour encoder des structures de données. Ce format de données compact est utilisé en interne chez Google des échanges de données. Etant basé sur la déclaration d'une structure de données dans un idl, protobuf possède plusieurs implémentation et est ainsi utilisable dans plusieurs langage. En java, la génération du code cible se fait avec ant. Mais bien sur reste utilisable avec maven par le plugin ant.
Nous allons reprendre notre Hello qui avait d'exemple. Voici sa structure protobuf :

package nfrancois.poc;

option java_package = "nfrancois.poc.protobuf.model";
option java_outer_classname = "HelloProto";

message Hello {
  required string name = 1;
  required string message = 2;
}


La structure se comprend assez facilement. Attention par contre, au trompeur package de 1ère ligne, qui n'est pas lié à la notion de package que nous avons en java. Il sert comme espace de nommage et éviter des collisions de nom si plusieurs objets protobuf portent le même nom. Puisque depuis cette idl, je pourrai aussi bien générer en C++ ou un autre langage, le vrai nom de package java est indiqué par l'option "java_package", de la même façon pour le nom de classe qui va tout encapsuler qui sera "java_outer_classname"
Pour plus d'information sur protobuf, je vous invite à consulter sa page google code.
Le générateur protobuf générera un fichier HelloProto.java, qui permettra de manipuler les Hello : création via pattern builder, encodage/désencodage, ... Le "vrai" Hello sera encapuslé au sein de ce dernier. Comme je disais, je génère le java par le ant plugin de maven :

<plugin>
 <groupid>org.apache.maven.plugins</groupId>
 <artifactid>maven-antrun-plugin</artifactId>
 <version>1.6</version>
 <executions>
  <execution>
   <id>generate-sources</id>
   <phase>generate-sources</phase>
   <configuration>
    <target>
     <exec executable='protoc'>
             <arg value='--java_out=src/main/java' />
             <arg value='src/main/resources/Hello.proto' />
             </exec>
    </target>
   </configuration>
   <goals>
    <goal>run</goal>
   </goals>
  </execution>     
 </executions>
</plugin>


et bien sûr des dépendances protobuf

<dependency>
    <groupid>com.google.protobuf</groupId>
    <artifactid>protobuf-java</artifactId>
    <version>2.4.0a</version>
</dependency>


Le contrat de test sera assez proche de se que nous avions dans les tests précédents :

@Test
public void shoulReplyHello(){
 // Given
 String message = "Hello";
 String name ="Nicolas";
 Hello hello = HelloProto.Hello.newBuilder().setName(name).setMessage(message).build();
 when(helloServiceMock.saysHelloToSomeone("Nicolas")).thenReturn(hello);
 // When
 ClientResponse response = resource().path("hello").path(name).get(ClientResponse.class);
 // Then
 verify(helloServiceMock).saysHelloToSomeone(name);
 assertThat(response.getClientResponseStatus()).isEqualTo(Status.OK);
 assertThat(response.getType().toString()).isEqualTo("application/x-protobuf");
 Hello entity = response.getEntity(Hello.class);
 assertThat(entity).isNotNull().isEqualTo(hello);
}


La resource REST, elle aussi va peut évoluer :

@Path("hello")
@Singleton
@Produces("application/x-protobuf")
public class HelloResource {
 
 @Inject
 private HelloService helloService;
 
 @GET
 @Path("/{name}")
 public Hello reply(@PathParam("name") String name){
  return helloService.saysHelloToSomeone(name);
 }
 
 public void setHelloService(HelloService helloService) {
  this.helloService = helloService;
 }
 
}


La difficulté à laquelle il faut se confronter, c'est que Jersey ne permet pas de gérer de base le protobuf… Pas grave, on va s'occuper de faire le lien entre l'encodage/désencodage de protobuf et Jersey.

Commençons par le reader qui s'occupe de désencoder le protobuff. Pour celà, nous devons implémenter l'interface MessageBodyReader où nous aurons du code technique protobuf.

@Provider
@Consumes("application/x-protobuf")
@Singleton
public class ProtobufMessageBodyReader implements MessageBodyReader<Message> {

 public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations,
                                                            MediaType mediaType) {
  return Message.class.isAssignableFrom(type);
 }

 public Message readFrom(Class<Message> type, Type genericType, Annotation[] annotations, 
    MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
    throws IOException, WebApplicationException {
  try {
   Method newBuilder = type.getMethod("newBuilder");
   GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(type);
   return builder.mergeFrom(entityStream).build();
  } catch (Exception e) {
   throw new WebApplicationException(e);
  }
 }

}



C'est par le content type "application/x-protobuf" que JAX-RS fera matcher le type le reader/writer à l'entrée/sortie de la resource. Pour l'encodage, c'est l'interface MessageBodyWriter qu'il faut implémenter.

@Provider
@Produces("application/x-protobuf")
@Singleton
public class ProtobufMessageBodyWriter implements MessageBodyWriter<Message> {
 public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations,
                                                              MediaType mediaType) {
  return Message.class.isAssignableFrom(type);
 }

 private Map<Object, byte[]> buffer = new WeakHashMap<Object, byte[]>();

 public long getSize(Message m, Class<?> type, Type genericType, Annotation[] annotations, 
                                                                 MediaType mediaType) {
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  try {
   m.writeTo(baos);
  } catch (IOException e) {
   return -1;
  }
  byte[] bytes = baos.toByteArray();
  buffer.put(m, bytes);
  return bytes.length;
 }

 public void writeTo(Message m, Class type, Type genericType, Annotation[] annotations, 
                MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream)
                throws IOException, WebApplicationException {
  entityStream.write(buffer.remove(m));
 }
}


La configuration de test, quant à elle sera un peu plus complexe, car il faut que la partie cliente puisse désencoder toute seule le protobuf :

protected AppDescriptor configure() {
 ClientConfig clientConfig = new DefaultClientConfig();
 clientConfig.getClasses().add(ProtobufMessageBodyReader.class);
 clientConfig.getClasses().add(ProtobufMessageBodyWriter.class);
 injector = Guice.createInjector(new ServletModule() {
 @Override
 protected void configureServlets() {
  bind(ProtobufMessageBodyReader.class);
  bind(ProtobufMessageBodyWriter.class);
  bind(HelloResource.class);
  serve("/*").with(GuiceContainer.class);
  }
 }); 
 return new WebAppDescriptor.Builder()
          .contextListenerClass(GuiceTestConfig.class)
          .filterClass(GuiceFilter.class)
          .clientConfig(clientConfig)
          .servletPath("/")
          .build();
}


Le code complet est ici.

samedi 16 avril 2011

Du Jersey, du Guice et de l'App Engine 3/3

Et pour finir cette série d'article, nous allons nous intéresser à la génération de JSon avec Jersey et bien sûr à sa testabilité.

Le xml, c'est bien gentil, mais dans des échanges REST ça peut être un peu lourd, surtout si le consommateur est un appareil mobile. La génération JSon avec Jersey peut s'appuyer sur JAX-B. Et oui, c'est justement pour cela que l'on s'en est occupé dans le précédant article. Le mapping, lui, ne change pas.

La resource ne nécessite qu'un petit changement :

 @GET
 @Path("{name}")
 @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) 
 public Hello reply(@PathParam("name") String name){
  return helloService.saysHelloToSomeone(name);
 }

Comme on est sympa, on permet de renvoyer soit du Json, soit du Xml, c'est le consommateur qui décide. Par défaut, c'est le 1er format qui est choisit, soit le JSon.

La génération JSon va nécessiter un peu de configuration, principalement à cause du type de JSon généré. C'est le ContextResolver qui va s'occuper de ça :

@Provider
@Singleton
public class JAXBContextResolver implements ContextResolver<JAXBContext> {

 /** Package that contains object that can be mapped */
 private static final String JAXB_OBJECT_PACKAGE = Hello.class.getPackage().getName();

 private final JAXBContext context;

 public JAXBContextResolver() throws Exception {
  this.context = new JSONJAXBContext(JSONConfiguration.natural().build(), 
                                     JAXB_OBJECT_PACKAGE);
 }

 @Override
 public JAXBContext getContext(Class<?> objectType) {
  if(objectType.getPackage().getName().equals(JAXB_OBJECT_PACKAGE)){
   return context;
         }
  return null;
 }
}

Ici le type de JSon souhaité est le natural. Cet objet doit être passés dans le même package que les resources, il profitera ainsi lui aussi de la découverte automatique au démarrage de Guice. Ce resolver n'est pas obligatoire, sans lui, le JSon généré est par défaut en mode mapped.

La configuration des tests, va devoir évoluer un peu pour prendre en compte notre génération en ode natural. La méthode configure() devient :

@Override
 protected AppDescriptor configure() {
  ClientConfig clientConfig = new DefaultClientConfig();
  clientConfig.getClasses().add(JAXBContextResolver.class);
  injector = Guice.createInjector(new ServletModule() {
   @Override
   protected void configureServlets() {
    bind(getTestingResourceClass());
    bind(JAXBContextResolver.class);
    serve("/*").with(GuiceContainer.class);
   }
  }); 
  return new WebAppDescriptor.Builder()
           .contextListenerClass(GuiceTestConfig.class)
           .filterClass(GuiceFilter.class)
           .clientConfig(clientConfig)
           .servletPath("/")
           .build();
 }

Ainsi du coté serveur comme du coté client, les échanges seront dans le même format. Nos tests deviendront :

@Test
 public void shoulReplyHelloInXml(){
  doShoulReplyHello(MediaType.APPLICATION_XML_TYPE);
 }
 
 @Test
 public void shoulReplyHelloInJson(){
  doShoulReplyHello(MediaType.APPLICATION_JSON_TYPE);
 } 
 
 private void doShoulReplyHello(MediaType type){
  String message = "Hello";
  String name ="Nicolas";
  Hello hello = new Hello(message, name);
  when(helloServiceMock.saysHelloToSomeone("Nicolas")).thenReturn(hello);
  
  ClientResponse response = resource().path("hello").path(name)
                                      .accept(type).get(ClientResponse.class);
  
  verify(helloServiceMock).saysHelloToSomeone(name);
  assertThat(response.getClientResponseStatus()).isEqualTo(Status.OK);
  assertThat(response.getType()).isEqualTo(type);
  Hello entity = response.getEntity(Hello.class);
  assertThat(entity).isNotNull().isEqualTo(hello);  
  
 } 

Une des différenciation entre les types de JSon générés se fait sur la façon dont sont écrites les listes. En mode natural, nous avons par exemple : objet1, objet2, ... avec des objet {"attributA":"valeurA", ....}

Imaginons que nous avons une autre ressource qui par grande politesse retourne 2 Hellos :

@Path("doublehello")
@Singleton
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public class DoubleHelloResource {
 
 @Inject
 private HelloService helloService;
 
 @GET
 @Path("/{name}")
 public List<Hello> reply(@PathParam("name") String name){
  List<Hello> hellos = new ArrayList<Hello>();
  hellos.add(helloService.saysHelloToSomeone(name));
  hellos.add(helloService.saysHelloToSomeone(name));
  return hellos;
 }
 
}

Pour vérifier sa bonne génération, nous aurions le test suivant :

@Test
 public void shoudHaveTwoHello(){
  String message = "Hello";
  String name ="Nicolas";
  when(helloServiceMock.saysHelloToSomeone("Nicolas"))
                        .thenReturn(new Hello(message, name)); 
  ClientResponse response = resource().path("doublehello").path(name)
                                      .get(ClientResponse.class);
  assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
  assertThat(response.getType()).isEqualTo(MediaType.APPLICATION_JSON_TYPE);
  List<hello> hellos = response.getEntity(new GenericType<List<Hello>>(){});
  assertThat(hellos).isNotNull().hasSize(2);
 }
 
 @Test
 public void shoudBeInNaturalJson(){
  String message = "Hello";
  String name ="Nicolas";
  when(helloServiceMock.saysHelloToSomeone("Nicolas"))
                                .thenReturn(new Hello(message, name)); 
  ClientResponse response = resource().path("doublehello").path(name)
                                      .get(ClientResponse.class);
  assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
  assertThat(response.getType()).isEqualTo(MediaType.APPLICATION_JSON_TYPE);
  String hellos = response.getEntity(String.class);
  assertThat(hellos).isEqualTo(naturalHelloJSon(message, name));
 }
 
 public String naturalHelloJSon(String message, String name){
  StringBuilder sb = new StringBuilder();
  sb.append("[{\"message\":\"").append(message)
    .append("\",\"name\":\"").append(name).append("\"},");
  sb.append("{\"message\":\"").append(message)
    .append("\",\"name\":\"").append(name).append("\"}]");
  return sb.toString();
 }

Même s'il est un format intéressant, le JSon souffre d'un problème lié au javascript : celui du cross-domain qui fait que l'on ne peut pas interroger un autre domain que celui de la page web. <a href="http://en.wikipedia.org/wiki/JSONP">JSonP</a> permet d'évincer cette contrainte.

Jersey permet aussi de générer ce type de réponse mais un peu moins facilement. Nous allons créer une nouvelle méthode pour ce type de réponse :

 @GET
 @Path("{name}.jsonp")
 @Produces("application/x-javascript")
 public JSONWithPadding replyWithJsonP(@PathParam("name") String name,
           @QueryParam("callback") @DefaultValue(CALLBACK_DEFAULT_NAME) String callback){
  Hello hello = helloService.saysHelloToSomeone(name);
  return new JSONWithPadding(hello, callback);
 } 

Son test reste dans l'optique des précédents :

@Test
 public void shoudBeJsonpWithCallbackNameParam(){
  String message = "Hello";
  String name ="Nicolas";
  when(helloServiceMock.saysHelloToSomeone("Nicolas")).thenReturn(new Hello(message, name));
  String callbackName = "monCallback";
  
  ClientResponse response = resource().path("hello").path(name+".jsonp")
                                      .queryParam("callback", callbackName)
                                        .get(ClientResponse.class);
  assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
  assertThat(response.getType().toString()).isEqualTo("application/x-javascript");
  assertThat(response.getEntity(String.class)).isNotNull().startsWith(callbackName);
 }

Je n'ai pas malheureusement pas trouvé comment unmarshmaller ce message.

Et voilà, ce tour d'horizon est fini, amusez vous bien avec ces quelques technos. Comme à chaque fois, le code source est disponible

dimanche 10 avril 2011

Du Jersey, du Guice et de l'App Engine 2/3

Dans le dernier article, nous disposions d'un service Hello World qui renvoyait du texte brut. Cette fois, nous allons lui ajouter la capacité à répondre du xml en sérialisant le message avec JAX-B.

Tout d'abord, notre nouvelle réponse sera faite par l'objet suivant :

XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Hello {
 
 private String message;
 private String name;
 
 public Hello(){
 }
 
 public Hello(String message, String name) {
  super();
  this.message = message;
  this.name = name;
 }
 
 public String getMessage() {
  return message;
 }
 
 public void setMessage(String message) {
  this.message = message;
 }
 
 public String getName() {
  return name;
 }
 
 public void setName(String name) {
  this.name = name;
 }
 
 @Override
 public int hashCode() {
  return Objects.hashCode(message, name);
 }
 
 @Override
 public boolean equals(Object obj) {
     if(obj instanceof Hello){
         final Hello other = (Hello) obj;
         return Objects.equal(message, other.message)
             && Objects.equal(name, other.name);
     } else{
         return false;
     }
 }
}

La ressource exposée évolue peu :

Path("hello")
@Singleton
@Produces(MediaType.APPLICATION_XML)
public class HelloResource {
 
 @Context 
 UriInfo uriInfo; 
 
 @Inject
 private HelloService helloService;
 
 @GET
 @Path("/{name}")
 public Hello reply(@PathParam("name") String name){
  return helloService.saysHelloToSomeone(name);
 }

 @POST
 public Response send(String name){
  Hello hello = helloService.sendHello(name);
  URI uri = uriInfo.getAbsolutePathBuilder().build();
  return Response.created(uri).entity(hello).build();
 }  
 
 
 public void setHelloService(HelloService helloService) {
  this.helloService = helloService;
 }
 
}

Les opérations de marshall/unmarshall sont opérées directement par Jersey lui même.

De même, les tests vont peu évoluer, seul le type de données attendu va changer. Nous aurons par exemple :

@Test
 public void shoulReplyHello(){
  String name ="Nicolas";
  String hello = "Hello "+name;
  when(helloServiceMock.saysHelloToSomeone(name)).thenReturn(hello);
  
  ClientResponse response = resource().path("hello").path(name).get(ClientResponse.class);
  
  verify(helloServiceMock).saysHelloToSomeone(name);
  assertThat(response.getClientResponseStatus()).isEqualTo(Status.OK);
  assertThat(response.getType()).isEqualTo(MediaType.TEXT_PLAIN_TYPE);
  assertThat(response.getEntity(String.class)).isEqualTo("Hello Nicolas");
  
 }

Et c'est tout, pour aujourd'hui ...

Bon ok, je reconnais, c'est un peu l'arnaque cet article, il y a peu de choses à faire. Mais n'est ce pas justement ça qui est intéressant, non ?

La prochaine fois, nous terminerons cette ballade autour de Jersey en générant du JSon.

Le code est disponible ici.

samedi 2 avril 2011

Du Jersey, du Guice et de l'App Engine 1/3

J'avais déjà parlé, dans de précédents articles, de la génération de xml et de json avec Jersey. Et si maintenant, on s'amusait à générer du protobuf ?
On parle de protobuf pour Protocol Buffers, une techno Google pour encoder des structures de données. Ce format de données compact est utilisé en interne chez Google des échanges de données. Etant basé sur la déclaration d'une structure de données dans un idl, protobuf possède plusieurs implémentation et est ainsi utilisable dans plusieurs langage. En java, la génération du code cible se fait avec ant. Mais bien sur reste utilisable avec maven par le plugin ant.
Nous allons reprendre notre Hello qui avait d'exemple. Voici sa structure protobuf :

package nfrancois.poc;

option java_package = "nfrancois.poc.protobuf.model";
option java_outer_classname = "HelloProto";

message Hello {
  required string name = 1;
  required string message = 2;
}


La structure se comprend assez facilement. Attention par contre, au trompeur package de 1ère ligne, qui n'est pas lié à la notion de package que nous avons en java. Il sert comme espace de nommage et éviter des collisions de nom si plusieurs objets protobuf portent le même nom. Puisque depuis cette idl, je pourrai aussi bien générer en C++ ou un autre langage, le vrai nom de package java est indiqué par l'option "java_package", de la même façon pour le nom de classe qui va tout encapsuler qui sera "java_outer_classname"
Pour plus d'information sur protobuf, je vous invite à consulter sa page google code.
Le générateur protobuf générera un fichier HelloProto.java, qui permettra de manipuler les Hello : création via pattern builder, encodage/désencodage, ... Le "vrai" Hello sera encapuslé au sein de ce dernier. Comme je disais, je génère le java par le ant plugin de maven :

<plugin>
 <groupid>org.apache.maven.plugins</groupId>
 <artifactid>maven-antrun-plugin</artifactId>
 <version>1.6</version>
 <executions>
  <execution>
   <id>generate-sources</id>
   <phase>generate-sources</phase>
   <configuration>
    <target>
     <exec executable='protoc'>
             <arg value='--java_out=src/main/java' />
             <arg value='src/main/resources/Hello.proto' />
             </exec>
    </target>
   </configuration>
   <goals>
    <goal>run</goal>
   </goals>
  </execution>     
 </executions>
</plugin>


et bien sûr des dépendances protobuf

<dependency>
    <groupid>com.google.protobuf</groupId>
    <artifactid>protobuf-java</artifactId>
    <version>2.4.0a</version>
</dependency>


Le contrat de test sera assez proche de se que nous avions dans les tests précédents :

@Test
public void shoulReplyHello(){
 // Given
 String message = "Hello";
 String name ="Nicolas";
 Hello hello = HelloProto.Hello.newBuilder().setName(name).setMessage(message).build();
 when(helloServiceMock.saysHelloToSomeone("Nicolas")).thenReturn(hello);
 // When
 ClientResponse response = resource().path("hello").path(name).get(ClientResponse.class);
 // Then
 verify(helloServiceMock).saysHelloToSomeone(name);
 assertThat(response.getClientResponseStatus()).isEqualTo(Status.OK);
 assertThat(response.getType().toString()).isEqualTo("application/x-protobuf");
 Hello entity = response.getEntity(Hello.class);
 assertThat(entity).isNotNull().isEqualTo(hello);
}


La resource REST, elle aussi va peut évoluer :

@Path("hello")
@Singleton
@Produces("application/x-protobuf")
public class HelloResource {
 
 @Inject
 private HelloService helloService;
 
 @GET
 @Path("/{name}")
 public Hello reply(@PathParam("name") String name){
  return helloService.saysHelloToSomeone(name);
 }
 
 public void setHelloService(HelloService helloService) {
  this.helloService = helloService;
 }
 
}


La difficulté à laquelle il faut se confronter, c'est que Jersey ne permet pas de gérer de base le protobuf… Pas grave, on va s'occuper de faire le lien entre l'encodage/désencodage de protobuf et Jersey.

Commençons par le reader qui s'occupe de désencoder le protobuff. Pour celà, nous devons implémenter l'interface MessageBodyReader où nous aurons du code technique protobuf.

@Provider
@Consumes("application/x-protobuf")
@Singleton
public class ProtobufMessageBodyReader implements MessageBodyReader<Message> {

 public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations,
                                                            MediaType mediaType) {
  return Message.class.isAssignableFrom(type);
 }

 public Message readFrom(Class<Message> type, Type genericType, Annotation[] annotations, 
    MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
    throws IOException, WebApplicationException {
  try {
   Method newBuilder = type.getMethod("newBuilder");
   GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(type);
   return builder.mergeFrom(entityStream).build();
  } catch (Exception e) {
   throw new WebApplicationException(e);
  }
 }

}



C'est par le content type "application/x-protobuf" que JAX-RS fera matcher le type le reader/writer à l'entrée/sortie de la resource. Pour l'encodage, c'est l'interface MessageBodyWriter qu'il faut implémenter.

@Provider
@Produces("application/x-protobuf")
@Singleton
public class ProtobufMessageBodyWriter implements MessageBodyWriter<Message> {
 public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations,
                                                              MediaType mediaType) {
  return Message.class.isAssignableFrom(type);
 }

 private Map<Object, byte[]> buffer = new WeakHashMap<Object, byte[]>();

 public long getSize(Message m, Class<?> type, Type genericType, Annotation[] annotations, 
                                                                 MediaType mediaType) {
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  try {
   m.writeTo(baos);
  } catch (IOException e) {
   return -1;
  }
  byte[] bytes = baos.toByteArray();
  buffer.put(m, bytes);
  return bytes.length;
 }

 public void writeTo(Message m, Class type, Type genericType, Annotation[] annotations, 
                MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream)
                throws IOException, WebApplicationException {
  entityStream.write(buffer.remove(m));
 }
}


La configuration de test, quant à elle sera un peu plus complexe, car il faut que la partie cliente puisse désencoder toute seule le protobuf :

protected AppDescriptor configure() {
 ClientConfig clientConfig = new DefaultClientConfig();
 clientConfig.getClasses().add(ProtobufMessageBodyReader.class);
 clientConfig.getClasses().add(ProtobufMessageBodyWriter.class);
 injector = Guice.createInjector(new ServletModule() {
 @Override
 protected void configureServlets() {
  bind(ProtobufMessageBodyReader.class);
  bind(ProtobufMessageBodyWriter.class);
  bind(HelloResource.class);
  serve("/*").with(GuiceContainer.class);
  }
 }); 
 return new WebAppDescriptor.Builder()
          .contextListenerClass(GuiceTestConfig.class)
          .filterClass(GuiceFilter.class)
          .clientConfig(clientConfig)
          .servletPath("/")
          .build();
}


Le code complet est ici.

samedi 26 mars 2011

Etendre les assertions de Fest Assert

C'est lors de la présentation de David Gageot sur les test au Paris JUG du mois de janvier que j'ai découvert Fest-Assert. J'ai rapidement été enthousiaste sur son utilisation. En plus de sa syntaxe proche d'un langage naturel, il permet d'étendre ses assertions en fonction de ses besoins. Voici 2 façons d'utiliser ce mécanisme :


Utilisation d'une Condition.

Ce cas de figure est à utiliser lorsque l'objet que je souhaite vérifier possède déjà son objet d'assertion (StringAssert, FileAsset, ... ) ou si celle ci est simple. Il faut pour cela étendre la classe Condition<T> et implémenter la méthode public boolean matches(<T> value). Imaginons pas exemple que je souhaite vérifier que ma liste contienne un nombre impair d'éléments. Je vais écrire la conditions suivantes :

private class IsListeTailleImpaireCondition extends Condition<List<?>> { 

 
     @Override 
     public boolean matches(List value) { 
          if(value == null){ 
               return false; 
          } else { 
               return value.size()%2==1; 
          } 
     } 

} 

Son utilisation s'avère très simplement :

assertThat(maListe).is(new IsListeTailleImpaireCondition()); 

ou :

assertThat(maListe).satifies(new IsListeTailleImpaireCondition()); 

La différente entre les 2, n'est qu'au niveau sémantique, la validation est équivalente. Et si on veut vérifier le contraire alors ? Rassurez vous, pas besoin d'écrire une condition inverse, Fest-Assert possède des méthodes pour ça : .isNot(...) ou .doesNotSatisfy(...)


Créer son objet d'assertion.

Ce cas de figure est adapté aux cas où mon objet ne possède pas son objet d'assertions. Là, depuis la version 1.4 qui date d'il y a peu, c'est devenu beaucoup plus simple. : il suffit d'étendre la classe GenericAssert et d'implémenter les méthodes que je souhaite, sans oublier bien sûr de retourner une instance de l'objet d'assertion afin de pouvoir chaîner les méthodes. Imaginons que je souhaite développer mes assertions sur DateTime de jodatime :

import static org.fest.assertions.Formatting.inBrackets; 

import static org.fest.util.Strings.concat; 
import org.fest.assertions.GenericAssert; 
import org.joda.time.DateTime; 

/**
 * Assertions for <code>{@link org.joda.time.DateTime}</code>.
 */ 
public class DateTimeAssert extends GenericAssert<DateTimeAssert, DateTime>  { 

/**
 * Creates a new {@link org.joda.time.DateTimeAssert}.
 * @param actual the target to verify.
 */  

 public DateTimeAssert(DateTime actual) { 
     super(DateTimeAssert.class, actual); 
 } 

 /**
  * Vérifie que le {@code org.joda.time.DateTimeAssert} est avant celui passé en paramètre.
  * @param Le {@code org.joda.time.DateTimeAssert} avec lequel on compare.
  * @return L'objet d'assertion.
  */ 

 public DateTimeAssert isBefore(DateTime expected){ 
     isNotNull();   
     if(actual.isBefore(expected)) { 
      return this; 
     } 
     failIfCustomMessageIsSet(); 
     throw failure(concat(actual(), " should be before to :", inBrackets(expected))); 
 } 

 /**
  * Vérifie que le {@code org.joda.time.DateTimeAssert} est avant ou égale à celui 
  *  passé en paramètre.
  * @param Le {@code org.joda.time.DateTimeAssert} avec lequel on compare.
  * @return L'objet d'assertion.
  */ 
 public DateTimeAssert isBeforeOrEquals(DateTime expected){ 
     isNotNull();   
     if(actual.compareTo(expected) <= 0) { 
      return this; 
     } 
     failIfCustomMessageIsSet(); 
     throw failure(concat(actual(), " should be before to :", inBrackets(expected))); 
 }  

 /**
  * Vérifie que le {@code org.joda.time.DateTimeAssert} est après
  * celui passé en paramètre.
  * @param Le {@code org.joda.time.DateTimeAssert} avec lequel on compare.
  * @return L'objet d'assertion.
  */  

 public DateTimeAssert isAfter(DateTime expected){ 
     isNotNull();   
     if(actual.isAfter(expected)) { 
      return this; 
     } 
     failIfCustomMessageIsSet(); 
     throw failure(concat(actual(), " should be after to :", inBrackets(expected))); 
 } 

 /**
  * Vérifie que le {@code org.joda.time.DateTimeAssert} est après ou égale à celui 
  * passé en paramètre.
  * @param Le {@code org.joda.time.DateTimeAssert} avec lequel on compare.
  * @return L'objet d'assertion.
  */  
 public DateTimeAssert isAfterOrEquals(DateTime expected){ 
     isNotNull();   
     if(actual.compareTo(expected) >= 0) { 
      return this; 
     } 
     failIfCustomMessageIsSet(); 
     throw failure(concat(actual(), " should be after to :", inBrackets(expected))); 
 }  

 /**
  * Vérifie que le {@code org.joda.time.DateTimeAssert} est compris dans l'intervale de
  * ceux passés en paramètre.
  * @param Le {@code org.joda.time.DateTimeAssert} de début d'intervallle
  * @param Le {@code org.joda.time.DateTimeAssert} de fin d'intervallle
  * @return L'objet d'assertion.
  */ 
 public DateTimeAssert isBetween(DateTime begin, DateTime end){ 
     isNotNull(); 
     if(actual.compareTo(begin) >= 0 && actual.compareTo(end) <= 0) { 
         return this; 
     } 
     throw failure(concat(actual(), " should be between :", 
                  inBrackets(begin), " and ", inBrackets(end)));   
 } 

 private String actual() { 
     return inBrackets(actual); 
 } 

} 

Pour m'en servir, je dois le rattacher à un point d'entrée, comme Assertions classe de base de Fest-Assert.

public class MyAssertions { 

 public static DateTimeAssert assertThat(DateTime actual) { 
     return new DateTimeAssert(actual); 
 } 

} 

Et pour finir, je n'aurais plus qu'à faire par exemple :

MyAssertions.assertThat(maDate).isBeetwen(debutPeriode,finPeriode); 

jeudi 4 février 2010

Le Paris JUG a 2 ans !

juggyannif02

Le Paris JUG fêtera son 2ème anniversaire mardi 9 février. Pour célébrer l'événement, l'équipe organise une soirée spéciale consacrée à l'Open-Source en France. Sacha Labourey, ancien CTO de JBoss fera la keynote. Jean-Michel Doudoux sera également présent afin de nous présenter les différentes licences permettant la diffusion libre de documentations.

Les inscriptions sont ouvertes, rendez-vous mardi au 108 boulevard Malesherbes !

Sfeir est sponsor de l'événement : c'est également l'occasion de venir nous rencontrer pendant la pause-buffet !

mercredi 2 décembre 2009

Le Motorola Droid (Milestone) débarque en France

Ce soir, j'ai pu assister à la soirée de présentation officielle du tout nouveau Motorola Droid (nommé Milestone en Europe), à l'occasion de sa commercialisation en France, et ce, dès ce soir.

Ce smartphone est un des plus attendus parmi les andro-phones : beaucoup y voient (espèrent) le tant attendu iphone killer. Pour preuve de sa popularité, à sa sortie aux états-unis (le 6 novembre), 250 000 exemplaires ont été vendus la première semaine...
Autre facteur faisant que ce téléphone attire l'attention (et pas des moindres) : il s'agit du premier téléphone équipé de Android 2.0.

Trêve de teasing, passons aux faits !

La présentation est lancée par Jacques Rames, président de Motorola France, qui nous annonce que :

  • Motorola a fait le choix d'Android en 2008, pour simplifier le développement multi-plateformes en interne et pour la facilité de déploiement d'applications (comparé à l'App Store d'Apple bien entendu).
  • Le Milestone est le deuxième téléphone Android de la marque et le début d'une longue série : Motorola projète de sortir pas moins de 10 smartphones Android en 2010, et souhaite devenir leader dans le domaine des smartphones (comme beaucoup me direz-vous).
Suite à cela, rueducommerce, qui sera - pour au moins les quelques semaines à venir - le vendeur exclusif du Motorola Milestone en France, nous annonce les tarifs :
  • à partir de 89 euros avec un forfait chez Bouygues Telecom ou SFR
  • beaucoup plus cher chez Virgin Mobile ou Orange (à partir de 189 euros et 219 euros !)
  • 549 euros le téléphone nu, sans abonnement
  Pour ceux qui le souhaitent, vous pouvez dès maintenant réserver ce téléphone en pré-commande chez rueducommerce. On nous a annoncé le début des livraisons mi-décembre (pour que tout le monde puisse avoir un joli Milestone sous son sapin de Noël ;)
Soit dit en passant, et ça aussi c'est Noël, jusqu'à fin décembre, pour le même prix, rueducommerce offre 60 euros d'accessoires en plus : un support multimédia (pour servir de mini-chaine hi-fi), et un support voiture (pour servir de GPS). Voir photo ci-contre.


Bien, l'aspect marketing et commercial étant passé, passons au côté technique !
Alors, qu'a t-il dans le ventre ce fameux Milestone ? Voici ses principales caractéristiques :
  • un écran très grand de 3,7 pouces (tout en restant compact)
  • le support du multi-touch
  • un processeur puissant cortex A8
  • une mémoire vive conséquente de 256 Mo (comme l'iphone 3GS)
  • un clavier physique AZERTY coulissant (pas comme l'iphone ;)
  • un appareil photo 5 MegaPixels avec flash double LED et auto-focus
  • un enregistreur vidéo (annoncé de qualité DVD !)
  • un mémoire interne de 8 Go extensible à 32 Go
  • WIFI, Bluetooth, USB 2.0, Micro-SD
  • un GPS, et un logiciel GPS développé par Motorola (malheureusement valable que 60 jours. Après, il faut passer à la caisse)
  • équipé de Android 2.0
  • équipé d'un navigateur intégrant Flash 10 (on va en reparler...)
Vous l'aurez compris, la liste des caractéristiques est plutôt alléchante, et il me tardait d'essayer concrètement l'appareil, pour voir s'il était à la hauteur de son impressionnante plaquette. Vous allez le voir, j'ai eu des bonnes et des mauvaises surprises. Petit retour d'expérience :
  • Tout d'abord, l'esthétique (c'est le premier truc qu'on voit) : on appréciera son grand écran, ses 4 boutons tactiles assez jolis, et une épaisseur assez fine pour un smartphone embarquant un clavier. Néanmoins, je le trouve un peu trop rectangulaire (peu arrondi), et le clavier est assez austère en comparaison au dernier LG GW620.
  • L'écran : l'écran est assez grand, et réagit très bien (écran capactif).
  • Le multi-touch : très fonctionnel pour le zoom sur les photos, et sur les sites internet. Par contre, ne marche bizarrement pas sur les maps (contrairement à un iphone...). Pour cela, il faut double-cliquer.
  • Le clavier : si je ne le trouve pas très esthétique, il est pour autant très efficace, le toucher est agréable et réactif.
  • La rapidité/puissance : globalement, la navigation est fluide et précise (l'écran capacitif aidant). J'ai noté toutefois quelques ralentissements lorsqu'on est sur le slideshow de photos.
  • Les photos : très bonne qualité de photo, même dans un endroit sombre, le double-flash marche très bien, et pas de flou. Les photos sont ensuite partageables sur facebook, myspace, picasa, ...
  • Les vidéos : j'ai été bluffé par la qualité des vidéos prises ! De même pour le son. C'est fluide, de bonne résolution et il y a un stabilisateur d'image. J'ai vu notamment une vidéo d'une piscine où on voit tous les détails des vagues. Par ailleurs, les vidéos sont partageables sur Youtube d'un clic.

Mais, me direz-vous, on est sur un blog technique et orienté développement/technologies, non ? Alors parlons de la star de ce Milestone, Android 2.0 :
  • La recherche : première fonctionnalité testée, la recherche intégrée dans le système d'exploitation. Le test est faussé par le fait que le téléphone est pour ainsi dire vide, mais néanmoins c'est convaincant. En quelques lettres tapées, on retrouve les contacts, les applications, les musiques de notre téléphone. Puis on le voit, dans un deuxième temps, il va chercher sur internet pour compléter la liste. Les résultats sont rapides, très pratique !
  • MySign : voici typiquement l'application qui m'a beaucoup plu. On dessine une lettre au doigt (qui peut être en fait n'importe quel geste), et il ouvre l'application paramétrée ! Très rigolo, mais aussi très ingénieux comme système de raccourci. Ce qui est particulièrement intéressant, c'est qu'on peut définir nos propres gestes, et leurs applications associées.
  • Intégration de Flash 10 dans le navigateur : il s'agit là de ma grande déception. Annoncé partout sur les plaquettes de Motorola, lorsque l'on va avec le téléphone sur un site Flash comme http://beta.parleys.com, on obtient un joli message indiquant que Flash n'est pas supporté... J'ai essayé avec d'autres sites, même problème... C'était de loin la fonctionnalité que j'attendais le plus (notamment d'un point de vue performance), et là, j'ai été très surpris et déçu de constater que ce n'est même pas fonctionnel. Les commerciaux nous ont expliqué que ce n'était pas la bonne version, mais je n'ai pas trouvé leurs arguments très convaincants.
  • Vive GWT et l'HTML 5 : Par contre, une application GWT 2.0 et HTML 5, ça marche très bien ! La preuve avec cette superbe application développée par SFEIR (^^) et qui fonctionne très bien sur le Motorola Milestone.

mardi 24 novembre 2009

SLF4J & LOGBack : simplifiez-vous les logs


Mercredi dernier, lors de la première journée de conférences du Devoxx, Ceki Gülcü, nous a présenté deux framework de logs complémentaires SLF4J et logback.


SLF4J

Ceki Gülcü a d'abord commencé sa présentation par la présentation de SFL4J (The Simple Logging Facade for Java), qui consiste en une API (slf4j-api.jar) permettant d'harmoniser les appels de log dans le code Java quelle que soit l'implémentation choisie (log4j ou JUL par exemple). Il explique au passage la possibilité de brancher sur son application utilisant SLF4J une implémentation noop (no operation performed).

Le speaker (et créateur de SLF4J) présente ce dernier comme un potentiel doublon de commons-logging à quelques différences prêt comme le choix de l'implémentation choisie par le framework qui se fait automatiquement (dynamiquement) dans commons-logging et de manière manuelle (statique) dans SLF4J en important le jar adéquat dans le classpath :  slf4j-logj12.jar pour log4j, slf4j-jdk14.jar pour JUL (java.util.logging) ou encore logback-classic.jar pour utiliser logback.

Le speaker est ensuite passé aux choses plus concrètes en montrant quelques exemple d'appel SLF4J, il a notamment mis l'accent sur la possibilité d'utiliser des messages paramétrés qui ne seront construits (i.e. qui ne consommeront de ressources) que s'il doivent être affichés. Pour démontrer son propos il a donné l'exemple suivant :

La vieille méthode La méthode moins naïve mais verbeuse La méthode SLF4J, intelligente et concise
logger.debug("Nom="+nom);
if(logger.isDebugEnabled()){
    logger.debug("Nom="+nom);
}
logger.debug("Nom={}",nom);

Il a ensuite abordé les autres fonctionnalités offertes par SLF4J, parmis lesquelles :

  • L'accès au MDC (Mapped Diagnostic Context) qui permet d'attacher des variables de log à un Thread comme par exemple le login de l'utilisateur ayant fait la requête permettant ainsi de suivre les logs de sa session de manière triviale même au sein de logs complètement entrelacés. Les informations stoquées dans le MDC sont ensuite utilisables directement dans les patterns de log utilisés dans la configuration de la couche de logging.

  • Les Markers hiérarchisés qui permettent en quelque sorte d'affecter des tags aux différents logs. Les applications sont évidemment nombreuses mais Ceki Gülcü a donné un exemple assez simple où les Marker sont utilisés pour marquer les logs "confidentiels" et ou les différents Appender encryptent ces logs "confidentiels". Grâce aux Markers il est donc possible de créer des comportements spécifiques quelle que soit l'origine du log.

SLF4J a ensuite été abordé toujours sous l'angle d'un framework d'uniformisation des logs applicatifs mais cette fois-ci en regardant l'intégration de ce dernier sur des projets utilisant déjà un pou plusieurs systèmes de logs. Il est aisin possible de créer une véritable passerelle entre commons-logging, log4j, JUL avec SLF4J afin de centraliser la gestion et la configuration des logs d'une application. Pour cela il suffit de remplacer les jar d'implémentation du (des) système(s) utilisés (comme commons-logging.jar ou log4j.jar) par des jar d'interception de logs (respectivement jcl-over-slf4j.jar et log4j-over-slf4j.jar). Dans le cas de JUL il faut cependant faire un petit effort de paramètrage (déclaration d'un logger dans le rootLogger).

Pour ceux qui auraient simplement envie de remplacer (et non pas aggreger) le système de logs de leur application, Ceki Gülcü a créé un utilitaire simple de migration vers SLF4J : le SLF4J Migrator

Logback

La créateur du framework nous a d'abord mis dans le bain en définissant LOGBack comme le successeur de Log4J, expliquant brièvement que LOGBack est simplement une évolution de ce dernier (par de rupture conceptuelle).

LogBack est divisé en 3 modules :
  • Logback Core : Module de base étendu par les deux autres modules
  • Logback Classic : Module de log des applications Java (implémente les API SLF4J décrites précédemment)
  • Logback Access : Module d'accès aux logs du conteneur de Servlet (Tomcat, Jetty)

Logback utilise Joran en ce qui concerne la configuration des logs, ce qui signifie qu'il est possible de décrire énormément de choses dans la configuration (contrairement aux configurations sous forme de XML répondant à une DTD statique ou de fichiers properties). il est par ailleurs possible de gérer les inclusions de morceaux de configurations et ainsi rendre le paramétrage des logs extrêmement modulaires au sein d'un projet de grande taille.

Durant sa démonstration des possibilité de logback, le speaker a aussi montrer qu'il est possible de publier des MBeans spécifiques à logback dans JMX et ainsi contrôler les logs dynamiquement via une console comme JConsole (c'est d'ailleurs comme ça qu'il rafraichissait son instance de logback lors des démos).

Filters

Logback offre, à l'instar de log4j, la possibilité d'utiliser des Filtres au sein de la configuration des logs, ce qui permet de prendre (ou non) des logs en fonction de leur correspondance à un filtre. Il est possible de créer des filtres sur des expressions Java complexes (grâce à Juanino qui compile les expression java contenues dans la configuration). On peut par exemple écrire une configuration comme celle-ci avec logback : 

<
appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
      
<evaluator name="myEval">
        
<expression>message.contains("contenu recherché")</expression>
      
</evaluator>
      
<OnMismatch>NEUTRAL</OnMismatch>
      
<OnMatch>DENY</OnMatch>
    
</filter>
    
<layout>
      
<pattern>
        %-4relative [%thread] %-5level %logger - %msg%n
      
</pattern>
    
</layout>
</appender>

Les expressions n'ont cependant à disposition que les informations contenues dans le LoggingEvent (dont par exemple le MDC, le timestamp de log, le logger, le marker racine ...). Pour plus d'informations sur l'utilisation des filtres, la doc se trouvent ici
Il existe aussi un tpe un peu particulier de Filtre dans logback qui sont les TurboFilter. ces filtres ne sont pas attachés à un appender particulier et sont donc appelés à chaque fois que le système doit créer une évènement de log (donc très tôt dans le processus de log). Il sont utilisés, comme leur nom l'indique, pour accélérer la prise de décision dans la gestion des filtres puisque si un appel au logger ne sera pas loggué à cause d'un TurboFilter (DENIED) alors aucun évènement ne sera diffusé dans le système. Les TurboFilter peuvent par exemple ressembler à ceci :

<
turboFilter class="ch.qos.logback.classic.turbo.MDCFilter">
    
<MDCKey>login</MDCKey>
    
<Value>bobby</Value>
    
<OnMatch>ACCEPT</OnMatch>
</turboFilter>

<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
    
<Marker>inutile</Marker>
    
<OnMatch>DENY</OnMatch>
</turboFilter>

Ceki Gülcü a poursuivi ses démonstrations avec le très intéressant SiftingAppender qui est capable d'encapsuler un appender paramétré (donc plusieurs appender différents au runtime) en fonction d'attributs qui peuvent provenir du MDC (ou d'une valeur par défaut). 
Grâce à ce dernier, il est par exemple possible de créer un appender par login ou par rôle dans une application de manière très simple et sans toucher ou presque au code Java. L'appender suivant définit par exemple un appender par rôle utilisateur en fonction de la valeur role (rôle de l'utilisateur exécutant la requête) contenue dans le MDC :

<configuration>
  
<appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
    
<discriminator>
      
<Key>role</Key>
      
<DefaultValue>ROLE_USER</DefaultValue>
    
</discriminator>
    
<sift>
      
<appender name="FILE-${role}" class="ch.qos.logback.core.FileAppender">
        
<File>${role}.log</File>
        
<Append>true</Append>
        
<layout class="ch.qos.logback.classic.PatternLayout">
          
<Pattern>%d [%thread] %level %mdc %logger{35} - %msg%n</Pattern>
        
</layout>
      
</appender>
    
</sift>
  
</appender>

  
<root level="DEBUG">
    
<appender-ref ref="SIFT" />
  
</root>
</configuration>

Cette configuration stocke dans le fichier ROLE_USER.log les logs des utilisateurs n'ayant pas de rôle défini dans le MDC. On voit bien ici que plusieurs Appenders vont être instanciés avec chacun un nom différent (FILE-ROLE_USER pour l'Appender par défaut).

Ceki Gülcü a enfin terminé en soulignant une petite fonctionnalités tout à fait intéressante de logback qui permet de suffixer les lignes de logs d'une stacktrace d'erreur par le nom et la version du jar utilisé, ce qui permet lors du debug d'erreur de récupérer instantanément cette information cruciale. 

Exemple de log généré : 
java.lang.NullPointerException at com.xyz.Wombat(Wombat.java:57) ~[wombat-1.3.jar:1.3] 
at com.xyz.Wombat(Wombat.java:76) ~[wombat-1.3.jar:1.3] 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.5.0_06]
...

Synthèse

Pour terminer, nous pouvons dire que, étant nous mêmes utilisateurs de log4j sur nos projets quotidiens, Ceki Gülcü nous a convaincu que logback est bel et bien une évolution de Log4j (et non pas une révolution) et qu'il semble très attrayant de tenter de passer à ce nouveau framework (qui propose qui plus est nativement les API SLF4J) 
A essayer donc !

Ressources

Blog de Ceki Gulcu : http://ceki.blogspot.com/
Une présentation du Jazzon09 quasi-similaire à celle du Devoxx par le même speaker : http://beta.parleys.com/#id=357&st=5

lundi 23 novembre 2009

Atmosphere, atmosphere


Au devoxx de cette année nous avons pu assister à la présentation du framework Atmosphere par Jean-François Arcand, créateur du framework et Paul Sandoz, contributeur sur le projet Jersey utilisé par Atmosphere en ce qui concerne les aspects REST.

Après une rapide présentation des concepts liés aux architectures PUSH pour les applications WEB. Les deux speakers sont rentrés dans le vif du sujet en développant en direct une petite application permettant de démontrer les possibilités offertes par Atmosphere.



Le PUSH ?

Dans les applications WEB, le PUSH correspond à l'utilisation des protocoles WEB pour permettre aux différents clients (navigateurs généralement) de se voir notifier des informations de la part du serveur sans avoir à faire des requêtes périodiques sur ce dernier. Comme son nom l'indique, les informations sont poussées du serveur vers le(s) client(s) et non plus tirées par chaque client désireux d'y avoir accès. L'intérêt d'une telle technique réside dans la possibilité de voir se propager rapidement une modification de l'état du serveur et atteindre ainsi un pseudo temps-réel tout en économisant des échanges réseaux inutiles. Avec le PUSH on peut par exemple dans le cas d'un tchat, propager les nouveaux messages d'une discussion du serveur vers les clients connectés de manière quasi instantanée.
Lors de cette conférence Jean-François nous a décrit les trois types de communications existantes dans les applications WEB à savoir :
  • Polling (technique traditionnelle)
  • Ajax PUSH  ou Long Polling : ce que propose Atmosphere
  • Http Streaming : Une technique idéale théoriquement mais qui souffre de problème d'intégration avec les proxys notamment.
Atmosphere est un framework (le premier) à base de POJO proposant aux développeurs d'applications PUSH une couche de programmation masquant la complexité des serveurs Java dans ce domaine.
Pour développer la partie serveur d'une application, le framework est utilisable sur de nombreux serveurs : des conteneurs legers (Tomcat, Jetty), certains serveurs d'applications comme Glassfish et Weblogic, il est même disponible pour le Google App Engine. Concernant ce dernier, on est en droit de se demander comment peut fonctionner le Long Polling avec des requêtes censées durer moins de 30s ? Jean-François nous a donné la solution en expliquant qu'Atmosphere implémente sont propre système de continuation permettant de passer outre cette contrainte. Il faut aussi noter la compatibilité d'Atmosphere avec les Servlets 3.0.

En ce qui concerne la partie cliente des applications, de nombreux frameworks sont supportés dont GWT et Wicket. 
Lors de la présentation, les speakers se sont focalisés sur une sous-partie du framework à savoir les annotations disponibles pour les POJOs et les aspects REST intégrés via Jersey.

Lors de la démo, les deux conférenciers ont pu nous démontrer la simplicité avec laquelle il est possible de créer une application WEB asynchrone utilisant le PUSH. Ils ont insisté sur le fait d'utiliser de simples POJO et de les rendre manipulables via REST. On obtient par exemple des classes ressemblant à ceci :

@Path("/{topic}")
@Produces("text/plain;charset=ISO-8859-1")
public class PubSub {
    private @PathParam("topic") Broadcaster topic;
    @GET
    @Suspend
    public Broadcastable subscribe() {
        return new Broadcastable("OK",topic);
    }
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Broadcast
    public Broadcastable publish(@FormParam("message") String message){
        return new Broadcastable(message,topic);
    }
}
L'idée principale de cette démo était d'utiliser Atmosphere pour suspendre la connection client lorsqu'il s'incrit à un topic "test" en appelant http://mon_serveur/test. Un autre client peut alors publier des messages qui seront diffusés à tous les clients connectés sur ce topic en soumettant un simple formulaire HTML contenant un paramètre "message" sous forme textuelle.

Ce que nous aurons retenu

Atmosphere simplifie effectivement le travail des développeurs en ce qui concerne la gestion du PUSH dans une application Java. Il n'est pas nécessaire de refondre entièrement une application existante pour y intégrer Atmosphere, la plupart des problèmes d'intégration sont adressés par le framework (gestion des proxys pour les connections HTTP, les limitations de chacun des navigateurs).

Resources:
Le site du projet : http://atmosphere.dev.java.net
Blogs :
Twitter : 
    @atmosphere_java 
    @jfarcand 

Ludovic Meurillon et Vincent Bostoen

vendredi 20 novembre 2009

Analyse de code avec maven

Intro

Maven, outil de build que l’on ne présente plus, nous rend encore un immense service en nous proposant de générer un site de présentation du projet.

J’aimerais dans cet article vous montrer les différents rapports de code que l’on peut ainsi  agréger et déployer, afin de présenter le projet ou pour en améliorer la qualité.

Je vous propose d’utiliser comme exemple un projet Open source hébergé sur googlecode, nommé gwt-mvc http://code.google.com/p/gwt-mvc/, choisi au hasard J

Voici le résultat : http://gwt-mvc.googlecode.com/svn/site/0.3/index.html


Rapports

 

Voici les différents plugins utilisés :

maven-project-info-reports-plugin http://maven.apache.org/plugins/maven-project-info-reports-plugin/

Plugin principal du site, permet de sélectionner les rapports de base

 

maven-javadoc-plugin http://maven.apache.org/plugins/maven-javadoc-plugin/

Génère la javadoc du projet.

 

maven-jxr-plugin http://maven.apache.org/plugins/maven-jxr-plugin/

Présente le code source avec des liens entre les classes, afin de pouvoir naviguer dans le code en dehors d’un IDE, pratique pour les projets Open Source.

 

maven-surefire-report-plugin http://maven.apache.org/plugins/maven-surefire-plugin/

Rapport de passage des tests unitaires.

 

maven-pmd-plugin http://maven.apache.org/plugins/maven-pmd-plugin/

Rapport de code avec PMD. Cela permet de vérifier la conformité du code avec des règles de codage prédéfinies. Ces règles peuvent être très poussées, mais la plus représentative est "Dans un  block catch, si une exception est relancées, elle doit être construite avec l'exception intiale en tant que cause". Inclus également le rapport Copy Past Duplication, mettant en avant les duplications de code. Il est même possible de bloquer le build en cas de non-respect de règle.

cobertura-maven-plugin http://mojo.codehaus.org/cobertura-maven-plugin/

Rapport de couverture de test.

 

maven-dependency-plugin http://maven.apache.org/plugins/maven-dependency-plugin/

Analyse des dépendances directes et indirectes, et distinction des dépendances : utilisée directement mais sans déclaration (directe), déclarées mais non utilisées.

 

versions-maven-plugin http://mojo.codehaus.org/versions-maven-plugin/

Rapport de mise à jour des dépendances et des plugins.

 

dashboard-maven-plugin http://mojo.codehaus.org/dashboard-maven-plugin/

Agrège les résultats de certains des rapports précédents, et les présente avec de jolis graphiques.

 

Intégration à Eclipse

Ces rapports étant éloignés de l’IDE, l’idéal est de pouvoir retrouver ces mêmes résultats au plus près du code, afin d’avoir deux outils complémentaires.

 

M2clipse http://m2eclipse.sonatype.org/ http://m2eclipse.sonatype.org/update/

Ce plugin permettra à Eclipse d’interpréter la configuration maven afin de compiler le projet.

 

JUnit

Intégré nativement à Eclipse, il vous permet de passer vos tests unitaires.

 

Eclemma  http://www.eclemma.org/ http://update.eclemma.org/

Eclemma vous permet d’obtenir votre couverture de test en utilisant emma. (Cobertura etait utilisé dans les rapports)

 

PMD http://pmd.sourceforge.net/ http://pmd.sourceforge.net/eclipse

Permet d’effectuer les contrôles du respect des règles de codage. Il est important de configurer ces outils avec le même ruleset, et de choisir avec précaution ces règles.

Ici, j’ai utilisé les règles proposées par le plugin PMD eclipse.

 

Conseils

Fixer les numéros de versions des plugins utilisés, afin d’avoir un build répétable.

Placer vos mots de passe dans les fichiers .settings, pas dans le pom, ou alors choisissez le mode interactif (vos identifiants vous seront demandés pendant l’execution).

 

Trucs et astuces

Pour afficher l’arbre des dependances de votre projet :

mvn dependency:tree

(Inclus dans le rapport « Dependencies » mais tellement pratique)

 

Pour savoir si vous utilisez la dernière version de vos plugins (y compris les rapports) :

mvn versions:display-plugin-updates

(Inclus dans le rapport « Plugin Updates Report »)

 

Problèmes rencontrés

J’aurais aimé pouvoir faire le site-deploy en une seule fois, mais wagon-svn ne fournit pas encore l’option qui permet de spécifier un fichier de configuration appellé auto-props, permettant d’associer un mime-type à une extension de fichier.

https://wagon-svn.dev.java.net/issues/show_bug.cgi?id=4

J’ai donc été obligé de générer le site dans un premier temps, puis de modifier les propriétés mime-type dans un second temps.

 

Recherche d’ artifact

Je vous conseille également les sites suivants pour « retrouver » des artifacts, leurs différentes versions, et sur quel repository ils sont disponibles.

http://merobase.com/

http://mvnrepository.com/

http://www.mvnbrowser.com/

 

Il existe des dizaines de sites proposant ce service, mais ceux-là ont un truc en plus, je vous laisse les découvrir.

 

Sources

http://beta.parleys.com/#sl=1&st=5&id=625

http://maven.apache.org/guides/mini/guide-site.html

http://blog.fastconnect.fr/?p=275

 

Bonne génératon de site.

 

Pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"

            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

 

            <modelVersion>4.0.0</modelVersion>

            <groupId>com.googlecode.gwt-mvc</groupId>

            <artifactId>gwt-mvc</artifactId>

            <version>0.3</version>

            <packaging>jar</packaging>

            <name>gwt-mvc</name>

            <description>

                        gwt-mvc Project, an MVC layer on Google Web Toolkit

            </description>

            <url>http://code.google.com/p/gwt-mvc/</url>

            <licenses>

                        <license>

                                   <name>The Apache Software License, Version 2.0</name>

                                   <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>

                                   <distribution>gwt-mvc-repository</distribution>

                        </license>

            </licenses>

 

            <repositories>

                        <repository>

                                   <id>maven2-repository.dev.java.net</id>

                                   <name>Java.net Repository for Maven</name>

                                   <url>http://download.java.net/maven/2/</url>

                        </repository>

                        <repository>

                                   <id>gwt-maven-repository</id>

                                   <url>

                                               http://gwt-maven.googlecode.com/svn/trunk/mavenrepo

                                   </url>

                        </repository>

            </repositories>

 

            <scm>

                        <!-- http://maven.apache.org/scm/subversion.html -->

                        <connection>

                                   scm:svn:http://gwt-mvc.googlecode.com/svn/trunk/gwt-mvc

                        </connection>

                        <developerConnection>

                                   scm:svn:https://${username}:${password}@gwt-mvc.googlecode.com/svn/trunk/gwt-mvc

                        </developerConnection>

                        <url>http://code.google.com/p/gwt-mvc/source/browse/</url>

            </scm>

 

            <distributionManagement>

                        <repository>

                                   <id>gwt-mvc-repository</id>

                                   <url>svn:https://gwt-mvc.googlecode.com/svn/repository</url>

                        </repository>

                        <site>

                                   <id>gwt-mvc-site</id>

                                   <url>

                                               svn:https://gwt-mvc.googlecode.com/svn/site/${version}

                                   </url>

                        </site>

            </distributionManagement>

 

            <build>

                        <extensions>

                                   <extension>

                                               <groupId>org.jvnet.wagon-svn</groupId>

                                               <artifactId>wagon-svn</artifactId>

                                               <version>1.9</version>

                                   </extension>

                        </extensions>

                        <plugins>

                                   <plugin>

                                               <groupId>org.apache.maven.plugins</groupId>

                                               <artifactId>maven-compiler-plugin</artifactId>

 

                                               <configuration>

                                                           <source>1.5</source>

                                                           <target>1.5</target>

                                                           <compilerVersion>1.5</compilerVersion>

                                               </configuration>

                                   </plugin>

                        </plugins>

            </build>

 

            <dependencies>

 

                        <dependency>

                                   <groupId>com.google.gwt</groupId>

                                   <artifactId>gwt-user</artifactId>

                                   <version>1.6.4</version>

                                   <scope>provided</scope>

                        </dependency>

 

 

                        <!-- ControllerTestCase compilation -->

                        <dependency>

                                   <groupId>junit</groupId>

                                   <artifactId>junit</artifactId>

                                   <version>4.5</version>

                                   <scope>provided</scope>

                        </dependency>

                        <dependency>

                                   <groupId>org.jmock</groupId>

                                   <artifactId>jmock</artifactId>

                                   <version>2.5.0</version>

                                   <scope>provided</scope>

                        </dependency>

                        <dependency>

                                   <groupId>org.jmock</groupId>

                                   <artifactId>jmock-legacy</artifactId>

                                   <version>2.5.0</version>

                                   <scope>provided</scope>

                        </dependency>

 

            </dependencies>

 

            <reporting>

                        <plugins>

                                   <plugin>

                                               <groupId>org.apache.maven.plugins</groupId>

                                               <artifactId>

                                                           maven-project-info-reports-plugin

                                               </artifactId>

                                               <reportSets>

                                                           <reportSet>

                                                                       <reports>

                                                                                  <report>index</report>

                                                                                  <report>licence</report>

                                                                                  <report>dependencies</report>

                                                                                  <report>plugin-management</report>

                                                                                  <report>plugins</report>

                                                                                  <report>summary</report>

                                                                                   <report>scm</report>

                                                                       </reports>

                                                           </reportSet>

                                               </reportSets>

                                   </plugin>

                                   <plugin>

                                               <groupId>org.apache.maven.plugins</groupId>

                                               <artifactId>maven-javadoc-plugin</artifactId>

                                               <version>2.6</version>

                                               <reportSets>

                                                           <reportSet>

                                                                       <reports>

                                                                                  <report>javadoc</report>

                                                                                  <!-- <report>test-javadoc</report> -->

                                                                       </reports>

                                                           </reportSet>

                                               </reportSets>

                                   </plugin>

                                   <plugin>

                                               <groupId>org.apache.maven.plugins</groupId>

                                               <artifactId>maven-jxr-plugin</artifactId>

                                               <version>2.1</version>

                                               <reportSets>

                                                           <reportSet>

                                                                       <reports>

                                                                                  <report>jxr</report>

                                                                                  <!-- <report>test-jxr</report>-->

                                                                       </reports>

                                                           </reportSet>

                                               </reportSets>

                                   </plugin>

                                   <plugin>

                                               <groupId>org.apache.maven.plugins</groupId>

                                               <artifactId>maven-surefire-report-plugin</artifactId>

                                               <version>2.4.3</version>

                                   </plugin>

                                   <plugin>

                                               <groupId>org.apache.maven.plugins</groupId>

                                               <artifactId>maven-pmd-plugin</artifactId>

                                               <version>2.4</version>

                                               <configuration>

                                                           <targetJdk>1.5</targetJdk>

                                                           <rulesets>

                                                                       <ruleset>/pmd/pmd-plugin-rules.xml</ruleset>

                                                           </rulesets>

                                               </configuration>          

                                   </plugin>

                                   <plugin>

                                               <groupId>org.codehaus.mojo</groupId>

                                               <artifactId>cobertura-maven-plugin</artifactId>

                                               <version>2.3</version>

                                   </plugin>

                                   <plugin>

                                               <groupId>org.apache.maven.plugins</groupId>

                                               <artifactId>maven-dependency-plugin</artifactId>

                                   </plugin>

                                   <plugin>

                                               <groupId>org.codehaus.mojo</groupId>

                                               <artifactId>versions-maven-plugin</artifactId>

                                               <version>1.1</version>

                                               <reportSets>

                                                           <reportSet>

                                                                       <reports>

                                                                                  <report>dependency-updates-report</report>

                                                                                  <report>plugin-updates-report</report>

                                                                                  <!--                     <report>property-updates-report</report>-->

                                                                       </reports>

                                                           </reportSet>

                                               </reportSets>

                                   </plugin>

                                   <plugin>

                                               <groupId>org.codehaus.mojo</groupId>

                                               <artifactId>dashboard-maven-plugin</artifactId>

                                               <version>1.0.0-beta-1</version>

                                   </plugin>

                        </plugins>

 

            </reporting>

 

</project>

 

mercredi 18 novembre 2009

DEVOXX 2009 - Conference Day 1 - Keynote

Premier jour à DEVOXX 2009 pour SFEIR, et premier jour de la partie "Conference" de DEVOXX.

Ca commence fort : Stephan JANSSEN (principal organisateur de DEVOXX) demande s'il y a des gens de SFEIR dans la salle, en précisant qu'on est venu à 24 au total ! Nous sommes surpris de notre popularité !







Stephan JANSSEN enchaine alors par quelques chiffres clés afin de se rendre compte de l'importance de l'événement :
- 8e édition
- plus de 2500 inscrits
- 737 entreprises
- 212 étudiants
- 132 sessions
- 120 speakers
- 56 JUGs
- 36 pays
- 19 partenaires

Il poursuit sur la présentation de Parleys.com V3, la plate-forme de e-learning dont il est le principal contributeur, et qui fête aujourd'hui ses 3 ans. Cette version est actuellement disponible sur : http://beta.parleys.com
Au programme des nouveautés de cette V3 :
- la possibilité de créer des espaces
- la possibilité de personnaliser son espace (par CSS)
- la possibilité d'avoir sa propre URL (monnom.parleys.com) pour son espace

Au programme de la version suivante (V4) :
- un client iphone (Stephan souligne que c'est à cause du système de validation de l'Apple Store que cette évolution n'est pas présente dans la V3)
- un système de pay-per-view, qui permet au visionneur de rémunérer le speaker de la session.

Il a également annoncé que comme l'an dernier, toutes les vidéos de DEVOXX 2009 seront publiées sur parleys.com tout au long de l'année (à hauteur de deux sessions par semaine) et disponibles gratuitement.
Pour ceux qui seraient pressés d'avoir accès à toutes les vidéos, une formule payante (49 euros pour 6 mois d'accès illimité) sera possible et permettra seulement une semaine après DEVOXX 2009 d'avoir un accès complet et illimité à toutes les vidéos des conférences.
Courage au passage à l'équipe DEVOXX, car à mon avis, la semaine après DEVOXX, ils auront du pain sur la planche...

Après Parleys, un speaker Oracle a expliqué sa vision du futur de la plate-forme java.
Une démonstration a été faite de Weblogic DM (pour Dynamic Modules), qui permet la modularisation en utilisant OSGI.
Je ne m'étendrai pas sur sa présentation qui, à mon sens, a peu apporté.



Puis Robert Chinicci (spec lead de Java EE 6) a présenté les grandes lignes de Java EE 6.
Il a annoncé que la date de version finale de Java EE 6 sera le 10 décembre 2009.
Il s'est attardé sur les principales nouveautés de Java EE 6 :
- JAX-RS : l'API pour développer des web services RESTfull, en utilisant uniquement des simples classes java (POJO) et des annotations.
- Bean Validation (JSR 303) : l'API pour définir des contraintes par annotation directement sur les entités métier.
Il sera intégré avec JSF et JPA pour que la validation soit automatique dans les frameworks associés. Par ailleurs, on pourra étendre les contraintes en créant ses propres annotations de contraintes.


- Web Profile : le premier sous-profil Java EE. Ce profil est en fait une sous-partie de Java EE 6, qui inclut les principales APIs utilisées pour développer des sites web. En plus de Servlet/JSP/JSTL/JSF, on pourra y retrouver des APIs plus poussées comme Managed Beans, EJB 3.1 lite, JPA et JTA. Ainsi, avec un serveur d'applications implémentant ce profil, on pourra réaliser des applications relativement complètes. Par contre, je vois mal Tomcat implémenter EJB 3.1 lite, JPA et JTA... On verra l'adoption de ce web profile par les serveurs d'applications.
- Servlet 3.0 :
Ont été ici cités : les web fragments, le fichier web.xml désormais optionnel, la configuration de servlets par annotation, la possibilité d'initialisation de librairies partagées, la registration de servlets par programmation (au démarrage), et la possibilité d'intégrer des ressources statiques dans les JARs des frameworks web.
Pour plus de détails sur cette API, vous pouvez lire notre compte-rendu de la soirée Servlet 3 & JSF 2 au Paris JUG.
- Dependency Injection : API permettant de standardiser l'injection de dépendance (JSR 299 et JSR 330).
En plus de l'annotation @Resource (existante dans Java EE 5), a été rajoutée l'annotation @Inject.
Les beans sont découverts au démarrage de l'application.
Possibilité de parcourir le métamodel d'injection, par l'API BeanManager
- EJB 3.1 :
ajout de l'annotation @Singleton (pour un EJB ayant une unique instance)
ajout de l'annotation @Startup (pour l'initialisation d'un EJB au démarrage de l'application)
ajout de l'annotation @Asynchronous (pour déclarer l'invocation d'un EJB comme asynchrone)
possibilité de définir un EJB directement dans un WAR
API EJBContainer pour pouvoir démarrer/exécuter un conteneur EJB dans une application Java SE ou pour les tests unitaires
- JSF 2.0 :
standardisation des facelets
définition de managed beans par annotation
intégration d'AJAX
et même une API JavaScript fournie
Tout comme Servlet 3.0, pour plus de détails sur cette API, vous pouvez lire notre compte-rendu de la soirée Servlet 3 & JSF 2 au Paris JUG.

Une démonstration a ensuite été faite de GlassFish V3, qui est l'implémentation de référence de Java EE 6.
On a alors appris qu'un plugin pour Eclipse existait et la démo en a attesté.
De la démo, on retiendra :
- un démarrage de Glassfish V3 en 3 secondes chrono (merci OSGi)
- une application web sans fichier web.xml (servlet définie par annotation uniquement)
- rechargement à chaud : on enregistre la modification dans Eclipse, on fait F5 dans son navigateur et ça marche ! Le tout en conservant la session utilisateur...
- démonstration de l'ajout simple d'un EJB directement dans l'application web : un EJB simple POJO avec l'annotation @Stateless, une servlet l'intégrant en variable d'instance (@EJB MonEJB monEJB), un appel à l'EJB dans la méthode doGet() de la servlet, hop, on rafraichit le navigateur et ça marche ! Bluffant de simplicité... au point que la salle applaudit
- démonstration de l'intégration d'un module OSGI dans la même servlet, toujours avec aussi peu d'étapes, et une intégration simple par annotation, on recharge le navigateur, et ça marche... Toujours pas de redémarrage du serveur d'applications, vraiment bluffant...


Enfin, Chet Haase (de Adobe) a montré l'ensemble de la gamme des produits d'Adobe, démo à l'appui.
On retiendra :
- Flash 10.1 optimisé pour être compatible avec des smartphones
- l'empreinte mémoire de la VM Flash 10.1 est globalement 2 fois inférieure à celle de la VM Flash 10.0
- une démo a par ailleurs été faite sur un smartphone de l'application parleys.com (qui fait du streaming vidéo), qui était particulièrement fluide.
- BlackBerry/RIM et Google Android sont en train d'intégrer Flash dans leur système
- Pour Apple/iPhone, ils ont indiqué qu'un outil permettait de convertir une application Flash en application iPhone SDK (démo à l'appui...)
- AIR 2.0 apporte plus de rapidité, et ouverture directe des fichiers dans le système d'exploitation
- une démo assez bluffante de Flash Catalyst : transformation de fichiers PhotoShop en une application Flash/Flex en quelques étapes (pour autant, il s'agissait grossomodo de la même démonstration que l'an dernier)

Ainsi se termine ce premier keynote, qui ma foi, fut assez intéressant !
 

lundi 16 novembre 2009

SFEIR en force à DEVOXX 2009 !

Cette semaine, a lieu un événement important pour la communauté java : DEVOXX 2009.
Il s'agit de la deuxième plus grosse conférence mondiale (et la première européenne) autour des technologies java.

Pour la quatrième année consécutive, SFEIR sera présent à l'événement, et pas qu'un peu : pas moins de 20 collaborateurs SFEIR feront le déplacement pour participer à DEVOXX 2009 les mercredi 18 et jeudi 19 novembre !

Pendant ces deux jours, nous essaierons de vous faire partager au mieux l'événement, en publiant des billets sur insideIT relativement aux sessions présentées.

Donc, si vous n'avez pas eu la chance d'avoir votre billet pour DEVOXX 2009, suivez le blog insideIT !

En attendant, voici le programme prévu pour ces deux jours :
- mercredi 18 novembre : http://www.devoxx.com/display/DV09/Conf+Day+1
- jeudi 19 novembre : http://www.devoxx.com/display/DV09/Conf+Day+2

lundi 9 novembre 2009

Les rencontres spring 2009 : SpringSource Updates, keynote par Adrian Colyer

La première session fut animée par Adrian Colyer le CTO de springsource, qui nous a présenté une synthèse des nouveautés du « spring portofolio » et du positionnement de SpringSource dans l’écosystème Java Entreprise. En effet, il a essayé de défendre ce qui était devenu la devise de la compagnie c'est-à-dire «la guerre contre la complexité » en mettant l’accent sur le spectre des produits qu’offre désormais Springsource couvrant le «Build, Run, Manage».

Il a commencé par les nouveautés du «spring-portofolio » et notamment Springframework et sa nouvelle version majeure (la 3ème) qui ne devrait plus trop tarder (une GA est prévue en décembre). Ainsi, en énumérant les nouvelles fonctionnalités apportées à cette version telles que le support REST, l’Expression Langage (SpEL), JavaConfig ou encore l’intégration de la validation déclarative (JSR-303) il a insisté sur la simplicité d’utilisation de ces API/SPI et le respect des valeurs et bonnes pratiques instaurées par la communauté.

Ensuite, il est passé aux autres modules du portofolio dont une nouvelle release était en attente de celle de spring-3. Le premier fut, Spring-Integration qui passera en 2.0. Celui-ci a bénéficié du SpEL, et a vu sa bibliothèque d’adaptateurs bien étouffée (JDBC, TCP/UDP, RSS/ATOM, XMPP…); sans oublier l’implémentation d’encore plus d’« Enterprise Integration Patterns » (http://www.eaipatterns.com/).

Puis il a passé à Spring-Batch, insistant sur le travail fait en vue d’une meilleure intégration avec Spring-Integration, et le nouveau module qui verra bientôt le jour, Spring-Batch Admin. En parlant de nouveau né, c'est-à-dire n’ayant pas encore atteint de release finale, il a cité ROO, le générateur de code basé sur Spring et AspectJ. Qui offrait une alternative purement java à Grails. Et pour finir avec l’axe «Build», il a parlé de STS (Spring ToolSuite), et la bonne nouvelle, c’est que SpringSource est en entrain de travailler sur l’amélioration du support Groovy/Grails, espérons qu’eclipse en bénéficierai aussi.

Pour le «Run », c'est-à-dire les runtimes fournis par Springsource, outre dm server dont la version 2 est proche (GA annoncée fin 2009), il a cité tc server le conteneur web basé sur tomcat. Il a notamment parlé d'une autre nouveauté : Spring tc server Developer Edition (actuellement disponible en preview). C’est un tomcat additionné de Spring Insight, une console de monitoring et de profiling, permettant de plonger dans votre application Spring, et de vous afficher à la fois des informations globales sur les performances, comme une vue détaillée de chaque requête HTTP avec l'URL appelée, les paramètres, les services appelés, et les requêtes SQL appelées.

Partant des serveurs d'applications et de Spring tc server Developer Edition, il a alors effectué une transition naturelle vers le «manage» et Hyperic, qui offre de belles fonctionnalités de management et de monitoring pour plus de 75 technologies.

Pour finir, il a introduit la nouvelle offre née de l’intérêt que porte la compagnie à la vague du cloud computing et matérialisée par Cloud Foundry, qu’il a présenté par le terme « Accelerate time to value, as-a-service ». Il a insisté sur le fait qu’elle associe toute la flexibilité et le savoir-faire acquis par la communauté des produits springsource classiques (Opinionated Software) à la puissance des services cloud d’amazon (notamment EC2) ; cela tout en priorisant le souci de simplicité, avec les « deployment blueprints ».

dimanche 18 octobre 2009

Compte-rendu de la soirée JSF 2.0 / Servlet 3.0 au Paris JUG

Mardi dernier, a eu lieu la soirée JSF 2.0 / Servlet 3.0 au Paris JUG. Comme à l'accoutumée désormais, la salle était comble, Antonio nous a même annoncé que toutes les places étaient prises 24h après l'annonce officielle ! Un conseil donc, si vous souhaitez participer à la prochaine soirée Paris JUG (soirée Google le 10 novembre), ne tardez pas une fois les inscriptions ouvertes !


JSF 2.0

La première partie de la soirée était consacrée à JSF 2.0. En réalité, derrière le titre JSF 2.0, cette présentation montrait les concepts généraux JSF d'une part, et les nouveautés JSF 2.0 d'autre part. On pourra regretter dans ce choix d'intégrer une présentation plus générale de JSF, le fait de voir les nouveautés JSF 2.0 noyées dans la masse et certaines nouveautés peu ou pas expliquées, faute de temps.
Voici les principales nouveautés de JSF 2.0 que j'ai retenu de cette présentation :

  • Possibilité de faire de la validation en utilisant la JSR 303 (Bean Validation) :
    Désormais, en positionnant le tag <f:validateBean> dans vos vues, JSF exécute la validation d'un bean donné en utilisant les annotations JSR 303 positionnées sur chaque attribut du bean. Par ailleurs, Emmanuel Bernard (spec lead de la JSR 303) est intervenu à la fin de cette présentation pour nous expliquer plus en détail l'intérêt de cette spécification : les contraintes de validation sont définies à un seul endroit, l'entité métier, et sont réutilisées par toutes les couches de l'application - présentation, métier, persistance - notamment de manière automatique par les frameworks comme JSF 2.0 ou encore Hibernate. Il nous a également indiqué que la JSR devrait très prochainement être finalisée.
     
  • Nouveau scope 'view' pour les managed beans :
    En plus des scopes classiques application, session et request, un nouveau scope fait son apparition : le scope view. Un bean de scope view sera maintenu par le conteneur tant que l'utilisateur ne change pas de page. Ce scope est donc pratique lorsque l'on souhaite faire plusieurs allers-retours client/serveur avec la même page, et que l'on souhaite conserver l'état de cette page entre chaque aller-retour.
     
  • Possibilité de déclarer des managed beans par annotation :
    Avant, la déclaration de managed-beans devait obligatoirement être faite dans le fichier faces-config.xml. Désormais, il sera possible de déclarer un managed bean par annotation en positionnant @ManagedBean sur le bean en question. Le scope du managed bean devra également être précisé (ex: @RequestScope pour un managed bean de scope request)
     
  • Développement de composants facilité avec EZComp :
    JSF 2.0 apporte la simplification du développement de composants avec EZComp. Avec EZComp, on déclare l'interface d'un composant, puis son implémentation pour un type de rendu donné, et on n'a plus qu'à importer le composant dans nos vues JSF.
    Interface :
    <composite:interface>
    <composite:attribute name="qui" required="true"/>
    </composite:interface>

    Implémentation :
    <composite:implementation>
    <span>Hello #{cc.attrs.qui}</span>
    </composite:implementation>

    Utilisation :
    <html xmlns:ez="http://java.sun.com/jsf/composite/hello">

    <ez:hello qui="world" />

     
  • Gestion native d'AJAX :
    Avant JSF 2.0, pour faire de l'AJAX, il fallait passer par des librairies tierces comme RichFaces. JSF 2.0 fournit désormais le nécessaire out-of-the-box. Ainsi, avec la balise <f:ajax>, on peut facilement intégrer des comportements AJAX dans ses vues, comme la validation en temps réel d'un champ, et sans rechargement de page.
     
  • Templating : intégration de facelets dans JSF 2.0 :
    En JSF 1, il fallait faire appel à la librairie tierce facelets pour faire du templating, JSF 2.0 l'intègre désormais directement. Ainsi, pour faire du templating, il faut d'une part définir un template XHTML définissant le cadre commun de la page et la zone où est insérée le contenu spécifique de chaque vue. Puis dans chaque vue, il faut référencer le template utilisé, puis définir le contenu spécifique de la page.
     
  • Gestion avancée des ressources statiques :
    Il est désormais possible de positionner les ressources statiques soit dans /resources, soit dans /META-INF/resources au niveau des classes de l'application web, ou encore dans les JARs de l'application (de WEB-INF/lib). Cette nouveauté n'est pas sans rappeler celle de Servlet 3.0, comme on le verra plus loin. Au delà de ce mécanisme, il est également possible de versioner les ressources statiques, mais également de les internationaliser. Ainsi, pour une même image, on pourra avoir une version fr_monimage.gif et une autre en_monimage.gif. Ces ressources pourront alors être référencées dans les vues soit par tag, soit par EL.
     
  • Gestion de profils :
    Une nouveauté intéressante, car peu commune, la gestion de plusieurs profils d'utilisation : development, production et unitTest. Avec ces profils, on peut mettre du code ou du contenu conditionné par un profil d'utilisation. Ainsi, par exemple, on pourra en cas d'erreur, afficher la stacktrace dans la page en profil development, et afficher un joli message  d'erreur en profil production.
     
  • Accès aux vues par la méthode GET :
    Enfin, dernière nouveauté qui était fortement demandée par la communauté, les vues seront désormais accessibles par la méthode GET, et plus seulement par la méthode POST. Cela permettra notamment aux utilisateurs de pouvoir créer un favori sur une page donnée.

 

Servlet 3.0

La deuxième partie de soirée était consacrée aux nouveautés apportées par Servlet 3.0. Aux commandes de cette présentation, Rémy Maucherat, responsable de l'implémentation des APIs Servlet & JSP chez JBoss, et membre de l'expert group de la JSR 315 alias Servlet 3.0. Autant dire qu'il maitrisait son sujet !
Au milieu de toutes les nouveautés annoncées, nous avons appris que pas mal de modifications avaient été apportées à cette JSR la semaine dernière même, ce qui est assez surprenant étant donné que la finalisation de cette JSR est très proche.
Voici la liste des nouveautés que j'ai retenu :
  • Possibilité de définir les servlets, filters, listeners par annotation :
    On peut désormais définir une servlet uniquement en positionnant une annotation @WebServlet sur la servlet en question (avec les paramètres associés, notamment les urlPatterns auxquels elle répond). Il en est de même pour les filters et listeners. Ainsi, le fichier web.xml devient optionnel.
    Enfin, il est également possible au niveau d'une servlet, de définir les contraintes de sécurité associées par annotation.
     
  • Possibilité de définir les servlets, filters, listeners par web-fragments :
    Chaque JAR d'un framework donné présent dans WEB-INF/lib peut définir sa configuration XML spécifique dans un fichier META-INF/web-fragment.xml. Ainsi, il sera désormais possible d'ajouter un framework web donné par simple drag&drop du JAR dans WEB-INF/lib, plus besoin d'ajouter de la configuration dans web.xml. Par ailleurs, cette configuration par défaut d'un framework web donné est surchargeable dans le fichier web.xml. On pourra ainsi redéfinir uniquement un init-parameter du controller du framework, le conteneur web se chargera de faire la fusion des configurations.
    Enfin, il est possible de définir l'ordre de chargement des web-fragments, soit dans le fichier web-fragment.xml même (ordre relatif de chargement de ce fragment par rapport aux autres), soit dans le fichier web.xml (ordre absolu des web-fragments chargés).
     
  • Possibilité de définir les servlets, filters, listeners par programmation :
    Au moment du chargement de l'application, il est possible désormais d'ajouter par programmation des servlets, filters et listeners à partir du ServletContext, ce qui permettra des configurations dynamiques (par opposition à la configuration statique) et contextuelles (en fonction de paramétrage d'environnement par exemple). Un exemple d'utilisation qui me vient à l'esprit : les tests unitaires. On pourra ainsi imaginer l'ajout à chaud de la servlet de Cactus lorsqu'une system property est détectée au démarrage de l'application.
     
  • Possibilité de définir des ressources statiques dans un JAR :
    Dans certains cas, on souhaite ajouter dans notre application, un framework ou un outil de monitoring/administration qui a ses propres ressources statiques associées. Aujourd'hui, il faut manuellement ajouter ces ressources à nos ressources applicatives, ce qui est dommage. Pour répondre à cette problématique, il est désormais possible dans Servlet 3.0, d'inclure dans un JAR (de WEB-INF/lib) les ressources statiques associées dans le répertoire META-INF/resources. Ces ressources statiques seront accessibles depuis le web comme si elles étaient positionnées à la racine du WAR.
     
  • Possibilité d'initialiser les bibliothèques partagées :
    Au jour d'aujourd'hui, il y a un certain flou autour de l'initialisation des bibliothèques partagées par plusieurs applications au sein d'une instance de serveur d'applications. Désormais, il sera possible au niveau de la bibliothèque partagée d'avoir un initializer implémentant l'interface ServletContainerInitializer, ayant une méthode onStartup() appelée à l'initialisation de chaque application présente dans le serveur d'applications. Le servletContext de l'application en question sera passé en paramètre. Un usage intéressant que je vois pour cette fonctionnalité est pour les portails (au sens moteur de portlets). Un portail a souvent besoin de rajouter des servlets, des listeners ou des filtres spécifiques au sein des portlets qu'il manage, ce qui est dommage lorsque l'on souhaite avoir des portlets standard Portlet 1.0 ou 2.0. Grâce à ce mécanisme, plus celui permettant de définir des servlets/filters/listeners programmatiquement, le portail pourra rajouter à chaud au démarrage du serveur,ses composants spécifiques au niveau de chaque portlet. Ainsi le web.xml de chaque portlet restera standard Portlet 1.0 ou 2.0.
     
  • Possibilité d'exécution asynchrone des servlets :
    Probablement la plus grosse fonctionnalité : la gestion d'exécution asynchrone des servlets. Cette fonction permet de répondre à deux problématiques :
    • le mécanisme de push dans les applications de chat ou les jeux en ligne
    • dans les applications très haute charge, la possibilité de libérer un thread du pool de threads du serveur d'applications pendant le temps où on attend des retours asynchrones du BackOffice du SI, pour les agréger ensuite dans la réponse web.
    Ce mécanisme est très puissant, mais apporte également son lot de complexité. A utiliser donc uniquement si on en a vraiment besoin.
     
  • Gestion des formulaires multi-parties (upload de fichiers) :
    Récupérer côté serveur (simplement) les fichiers envoyés par un client via un formulaire était un manque important, qui avait jusqu'alors été comblé par la librairie Apache Commons FileUpload, largement utilisée. Servlet 3.0 reprend quasiment à l'identique les fonctionnalités permises par cette librairie.
     
  • Possibilité de contrôler le processus d'authentication par le conteneur :
    Un constat est le fait que les mécanismes d'authentification par le conteneur sont peu utilisés car peu flexibles, peu contrôlables. Partant de ce constat, de nouvelles méthodes ont été ajoutées dans l'interface ServletRequest afin de permettre aux développeurs de contrôler le mécanisme d'authentification du conteneur :
    • authenticate(response) : lance le mécanisme d'authentification défini du conteneur 
    • login (username, password) : lance le mécanisme d'authentification du conteneur à partir des identifiants passés en paramètre (nouveau type d'authentification : LOGIN)
    • logout() : permet de forcer la déconnexion de l'utilisateur en supprimant le principal de la session
       
  • Possibilité de personnalisation de la gestion des sessions :
    Désormais, dans la balise <session-config> du fichier web.xml, il est possible de personnaliser la gestion des sessions :
    • possibilité de modifier le nom du cookie de session (par défaut JSESSIONID)
    • possibilité de choisir le mécanisme de récupération de l'id de session : URL, COOKIE, SSL
    • possibilité de redéfinir la portée du cookie de session (par défaut : locale au contexte web de l'application). Cela permet notamment d'activer le partage de sessions entre plusieurs applications au sein d'un même serveur d'applications. Cela sera particulièrement utile pour les portails (encore une fois), pour permettre d'avoir une session commune entre toutes les portlets.
     

Conclusion

En conclusion, beaucoup de nouveautés pour ces deux versions majeures d'APIs, intégrant la spécification Java EE 6. Côté JSF 2.0, on appréciera le fait que Sun ait écouté la communauté (support natif d'AJAX, support de la méthode GET), et le fait d'avoir intégré certains frameworks existants et ayant fait leurs preuves comme Facelets. Mais pour moi, le plus impressionnant est côté Servlet 3.0 : on avait pas vu pareils changements depuis au moins Servlet 2.3 (avec l'arrivée des listeners et filters), et cela fait plaisir à voir. Pour moi, les maîtres mots sont flexibilité (avec quatre moyens de définir des servlets, filters et listeners) et puissance (notamment avec la nouvelle fonctionnalité d'exécution asynchrone des servlets).
Bien sûr, tout le monde ne tirera pas forcément partie de ces nouveautés et continuera à utiliser l'API Servlet comme au bon vieux temps. Mais, je pense que tout cela apportera de nouveaux frameworks, de nouveaux outils qui tireront profit au maximum des nouveautés de Servlet 3.0, et pourquoi pas, apporteront de nouveaux usages...



Références

Slides JSF 2.0
Slides Servlet 3.0

jeudi 11 juin 2009

Eric Evans au Paris JUG lundi 15 juin

Ce cours post pour vous signaler la venue d'Eric Evans au Paris JUG lundi 15 juin (ce lundi) à 19h30 pour une soirée exceptionnelle dans les locaux de l'EPITA (KB).

Eric viendra parler du Domain Driven Design dont il est le fondateur.

C'est une présentation du niveau des grandes conférences telles que Devoxx ou Jazoon, sauf que vous ne payez ni le transport ni la conférence :-)

Inscriptions ici : http://parisjug.org/xwiki/bin/view/Meeting/20090615

mercredi 1 avril 2009

Barcamp sur Android à la Cantine le samedi 28 mars 2009

SFEIR a participé au Barcamp sur Android à la Cantine le samedi 28 mars 2009. Elle a organisé des ateliers de découvertes sur plusieurs sujets d'android le matin du barcamp :

  • Kit de démarrage Android
  • Android Multimédia (2D, 3D, Son)
  • WebServices Android (Interactions avec les APIs Google)
  • Les 4 blocks d'une application Android
  • Démasquer une application android (créer un jeu en 5min)
  • MapActivity et GPS

Vous pouvez retrouver une bonne partie des présentations et codes sources fait lors de ces ateliers sur le nouveau site dédié à Android :

http://www.insideandroid.fr

Voici une vidéo faite pendant l'évènement :


Vidéo du Barcamp sur Android à la Cantine le 28 mars 2009

lundi 16 mars 2009

CR Paris JUG - Partie 2 : Web Sémantique

Suite du compte-rendu de la soirée Wicket & Web sémantique, le premier billet consacré à Wicket est disponible ici.

Alexandre Bertails d’Atos Origin nous a ensuite présenté les dernières avancées en matière de Web Sémantique (ce que devait être le Web 2 et que pourrait être le Web 3).

L’idée du Web Sémantique a germé en 1994, de l’inventeur même du web Tim Berners-Lee. La terminologie « Web Sémantique » ne reflète pas ce que c’est réellement, une version plus exacte pourrait être « Web de données », l’objectif étant de partager ces données, d’en faciliter l’accès, et ceci indépendamment de la logique dont elles pourraient être récupérées/traitées/affichées.

Lire la suite...

dimanche 15 mars 2009

CR Paris JUG - Partie 1 : Wicket

Mardi s’est tenue la réunion mensuelle du Paris JUG. Thèmes de la soirée : Wicket & Web sémantique.

L’équipe a commencé par quelques annonces :

  • Les inscriptions sont désormais obligatoires avec contrôle à l’entrée. Sous quelle forme ? On se cherche encore un peu, imprimer une confirmation d’inscription n’étant pas la solution la plus écologique.
  • Le sponsoring du Paris JUG est remis à zéro en mars, c’est l’occasion de devenir sponsor.
  • Javablackbelt fait une offre pour les juggers : 15 points sont offerts si vous passez par le JUG pour vous inscrire.
  • Un nouveau JUG est en train de voir le jour, le Ch’ti Jug, organisé par Julien Jakubowski et Cyril Lakech : http://chtijug.org/ pour plus d’informations ou directement sur la mailing-list.

Wicket

Carl Azoury et Nicolas André de Zenika nous ont ensuite présenté Wicket, et mis à part les petits problèmes techniques liés à la démo sans filets, on peut dire qu’ils l’ont très bien fait.

D’autre part, Wicket se veut un framework avec un très faible ticket d’entrée : le langage Java et le langage Html, rien d’autre. Pas de configuration XML, pas de configuration par properties, pas de pages JSP ou JSF. Et si on se contente d’utiliser les nombreux composants Wicket, permettant de dynamiser le rendu, pas besoin non plus de faire de JavaScript.

Lire la suite...

- page 1 de 3