vendredi 22 octobre 2010

Spring ROO 1.1








Nous avions vu il y a quelques temps ce que Spring ROO proposait dans une de ses toutes premieres versions.
Depuis j'ai suivi d'un oeil distrait les évolutions de ce framework. Cependant une annonce m'a particulièrement intéressée : Spring ROO intègre désormais GWT comme technologie de présentation.
GWT est décidément en vogue du côté des frameworks RAD en ce moment. Play aussi propose une intégration avec GWT via un module.

Voyons comment ROO a évolué en 1 an et demi. Nous allons créer le même projet que la dernière fois, une bibliothèque de films.

La syntaxe a un peu changé. Cette série de commandes permet de créer notre projet, nos entités et nos CRUD, puis de générer et lancer des tests :

mkdir films
cd films
roo
roo> project --topLevelPackage com.loicdescotte.coffeebean.films
roo> persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
roo> entity --class ~.Film --testAutomatically
roo> field string --fieldName titre --notNull
roo> field string --fieldName realisateur
roo> field date --fieldName dateSortie --type java.util.Date
roo> controller all --package ~.web
roo> selenium test --controller ~.web.FilmController
roo> gwt setup
roo> perform tests
roo> quit

Il est assez impressionnant de voir tout ce qui est généré quand on tape ces commandes.
On obtient un projet maven complet avec des services Spring, une IHM GWT et des tests JUnit et Selenium.
En tapant "help" dans le shell ROO on s’aperçoit qu'il existe un grand nombre de commandes et qu'il est possible de générer énormément de choses (provider JSON, listeners JMS, bundles OSGI ...).
Le code généré est toujours un mélange de classes Java et d'aspects écrits en AspectJ. Les aspects permettent d'enrichir le code Java, par exemple pour ajouter des fonctions de persistance aux objets du domaine.

Voici la classe java pour mon entité Film :
@RooJavaBean
@RooToString
@RooEntity
@Entity
public class Film {

    @NotNull
    private String titre;

    private String realisateur;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "S-")
    private Date dateSortie;
}

Vous remarquerez qu'ici on ne s'embête pas avec les getters/setters, ils seront ajoutés dynamiquement. On gagne donc en lisibilité.

A côté de ça on a un aspect pour la persistance de nos films (Film_ROO_Entity.aj):

privileged aspect Film_Roo_Entity {

 @PersistenceContext
    transient EntityManager Film.entityManager;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long Film.id;

      public static long Film.countFilms() {
        return entityManager().createQuery("select count(o) from Film o", Long.class).getSingleResult();
    }
    
    public static List<Film> Film.findAllFilms() {
        return entityManager().createQuery("select o from Film o", Film.class).getResultList();
    }
    
    public static Film Film.findFilm(Long id) {
        if (id == null) return null;
        return entityManager().find(Film.class, id);
    }

@Transactional
    public void Film.persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.persist(this);
    }
    
    @Transactional
    public void Film.remove() {
        if (this.entityManager == null) this.entityManager = entityManager();
        if (this.entityManager.contains(this)) {
            this.entityManager.remove(this);
        } else {
            Film attached = this.entityManager.find(this.getClass(), this.id);
            this.entityManager.remove(attached);
        }
    }

//...


Il y a aussi un aspect pour la méthode toString(), un autre pour les getters/setters.

Quand j'ai découvert ROO j'ai été un peu rebuté par ce mode de fonctionnement. Finalement je le trouve plutôt élégant, il permet de bien isoler les différentes responsabilités du code.

Taper la commande maven suivante permet de lancer l'application :
mvn gwt:run

Et voilà le résultat :



Il est également possible de déployer notre application sur le Cloud avec CloudFroundry (un service de SpringSource reposant sur l’infrastructure d'Amazon), en utilisant ce module.

Tout est donc fait pour qu'on puisse créer et déployer rapidement une application, à un bémol près : attention si vous prenez l'offre d'essai gratuit d'Amazon AWS. On peut vite basculer dans le payant si on dépasse les quotas, il ne semble pas y avoir de verrou sur le paiement comme chez Google.