Sélection de colonnes dans Hibernate

 Liste avec seulement quelques colonnes dans Hibernate

Les outils d’ORM (Hibernate, Ibatis, …) sont aujourd’hui à maturité et ne souffrent plus des problèmes de performance des premières versions. Le code SQL généré, ainsi que la transformation en objets, ont été très largement optimisés.

Cependant selon la taille de la grappe d’objet remontée, il peut subsister des problèmes de performance, liés au nombre et à la complexité des objets à créer. Le cas d’utilisation typique sur une application de gestion est l’affichage d’une liste d’objet complexe sur un écran de recherche.

Prenons le cas par exemple d’une liste de commande (que nous simplifions volontairement) :

public Class Commande {

private Destination destination;

private Set<LigneCommande> lignes;

private Client client;

...

}
Une requête Criteria qui permet de remonter la liste des commandes ressemble à ceci :
DetachedCriteria criteria = DetachedCriteria.forClass(Commande.class,"commande")

.createAlias("commande.Destination", "destination", CriteriaSpecification.LEFT_JOIN)

.createAlias("commande.Lignes", "lignes", CriteriaSpecification.LEFT_JOIN)

.createAlias("commande.Client", "client", CriteriaSpecification.INNER_JOIN);

List<Commande> listCommande = getHibernateTemplate().findByCriteria(criteria);
Cette requête remonte donc tous les objets Commande (toutes les colonnes de la table correspondante), ainsi que les objets liés (et donc toutes les colonnes associées). Dans le cas où la grappe d’objets est importante et composée de nombreux objets, le nombre de lignes remontées devient très important et la constitution des objets très coûteuse  Rappelons que nous souhaitons simplement afficher une liste avec seulement quelques colonnes… au moins 95% des données remontées ne nous servent donc à rien.

Depuis la version 3 d’Hibernate a été introduite la notion de Projection. Celle-ci va nous permettre non seulement de remonter seulement les colonnes qui nous intéressent mais également une liste d’objets non gérés par Hibernate ; par exemple nous allons pouvoir remonter directement une liste de DTO (data transfert object) en se basant sur le même objet criteria (forClass(Commande.class, »commande »)) :

On définit le DTO :

public class DealListDto implements Serializable  {
    private static final long serialVersionUID = 1L;

    private java.lang.String id;
    private String ref;
    private Date date;
    private String nom;
    private String prenom;
    private String destNom;
    ...
}
puis les propriétés que l’on souhaite remonter, ainsi que le bean avec lequel on veut les mapper :
criteria.setProjection(Projections.projectionList()

.add(Property.forName("commande.Id"), "id")

.add(Property.forName("commande.Ref"), "ref")

.add(Property.forName("commande.Date"), "date")

.add(Property.forName("client.Nom"), "nom")

.add(Property.forName("client.Prenom"), "prenom")

.add(Property.forName("destination.nom"), "destNom")

.setResultTransformer( Transformers.aliasToBean(DealListDto.class));

List<DealListDto> listCommande = getHibernateTemplate().findByCriteria(criteria);
Nous obtenons donc une liste de DealListDto, beaucoup plus légers, que nous pouvons  faire remonter directement sur la couche client.

Datasources en hosted mode avec GWT 1.6

Configuration des datasources en hosted mode avec GWT 1.6

La migration de GWT de la version 1.5 à la version 1.6 s’est accompagnée de changements en profondeur au niveau du hosted mode. En effet, celui-ci utilisait précédemment une version embarquée du serveur tomcat, qui a été remplacée dans la dernière version par jetty.

Ce changement a donc entraîné une restructuration au niveau de la configuration des projets et notamment de la déclaration des datasources *. Cet article va donc présenter la configuration des datasources en hosted mode avec GWT 1.6.

La première étape est de rajouter les jar jetty-naming-6.1.11.jar et jetty-plus-6.1.11.jar à notre projet. Ceux-ci permettront d’utiliser notre propre fichier de configuration de jetty. Si comme nous vous utilisez Maven pour gérer les dépendances de votre projet, rajoutez les deux entrées suivants à votre pom.xml :

<dependency>
<groupid>org.mortbay.jetty</groupid>
<artifactid>jetty-naming</artifactid>
<version>6.1.11</version>
</dependency>
<dependency>
<groupid>org.mortbay.jetty</groupid>
<artifactid>jetty-plus</artifactid>
<version>6.1.11</version>
</dependency>

Sinon, vous trouverez ces jars sur le site de jetty.
Il faut maintenant crée un fichier nommé jetty-web.xml qui contiendra la déclaration de nos datasources sous la forme suivante :

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure>
<New id="dataset1">
<Arg>java:comp/env/jdbc/dataset1</Arg> <Arg>
<New>
<Set name="Url">jdbc:mysql://localhost:3306/database1?autoReconnect=true</Set>
<Set name="User">username1</Set>
<Set name="Password">password1</Set>
</New>
</Arg>
</New>
<New id="dataset2">
<Arg>java:comp/env/jdbc/dataset2</Arg>
<Arg>
<New>
<Set name="Url">jdbc:mysql://localhost:3306/database2?autoReconnect=true</Set>
<Set name="User">username2</Set>
<Set name="Password">password2</Set>
</New>
</Arg>
</New>
</Configure>

C’est cette configuration qui va indiquer à quelle base de donnée correspond chacun des datasets, et les paramètres de connexion. Dans cette exemple, nous déclarons deux datasets qui utilisent les bases de donnée MySql database1 et database2 du serveur local.
Il faut ensuite référencer les datasources dans le web.xml pour que notre application soit en mesure de les utiliser :

<res-ref-name>java:comp/env/jdbc/dataset1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<res-ref-name>java:comp/env/jdbc/dataset2</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

Une fois cette étape réalisée, vous pouvez utiliser vos datasets au sein de votre application comme vous le feriez normalement :

DataSource source = (DataSource)ctx.lookup("java:comp/env/jdbc/dataset2");
Connection connection = source.getConnection();
//...

 

Caches applicatifs avec Spring et ehcache

La recherche de performances applicatives passe souvent par la mise en place de caches applicatifs.

Ces caches permettent de maintenir en mémoire les données souvent requêtées par les utilisateurs mais peu mises à jour (paramétrages, villes, …).
Spring offre la mise en place d’un tel cache assez facilement par l’intégration d’un framework tel que ehcache.

Dans le fichier configuration de Spring on ajoute les lignes suivantes :

<ehcache:config failQuietly="false" />
<ehcache:annotations>
<ehcache:caching id="test" cacheName="testCache" />
<ehcache:flushing id="test" cacheNames="testCache" when="after" />
</ehcache:annotations>

Dans le fichier configuration de ehcache.xml, on retrouve la définition du cache : nombre d’objet en cache, écriture sur disque, politique d’éviction,…Le cacheName et ce que l’on va retrouver dans le fichier de configuration de ehcache,
L’id et ce que l’on va retrouver dans l’annotation,
caching l’id est utilisé pour la mise en cache,
flushing l’id est utilisé pour la libération du cache.

<cache name="testCache" maxElementsInMemory="1000"overflowToDisk="true" eternal="true" memoryStoreEvictionPolicy="LFU"/>
On ajoute les annotations suivantes dans le source Java afin de les mettre en cache après le premier appel :
@CacheFlush(modelId = "test")

public String saveObject(Object objet) {…}

 

@Cacheable(modelId = "test")

public User findObject(String idObject) {…}

Caption Panel GWT

Les contraintes ergonomiques des IHM d’applications professionnelles sont bien plus souples que celles qui régissent la conception de portails de ventes en ligne.
L’offre Viaxeo proposant un moteur de génération de sites e-business intégrés in extenso dans son CRM multicanal, nous avons du développer les outils nous permettant de répondre efficacement aux canons graphiques actuels afin de nous conformer aux chartes graphiques de nos clients.

Le premier obstacle rencontré était inhérent à la physionomie rudimentaire de nos panels de bases. Point de formes géographiques fantaisistes ni d’habillage recherché sans passer par l’utilisation manuelle, au cas par cas, de groupes de widgets englobant et de feuilles de style.

GWT propose de palier à ces difficultés via le DecoratorPanel, un widget à 9 « conteneurs », 8 panels périphériques destinés à accueillir images et styles, et un SimplePanel central dévolu à l’ajout de contenu.
En voici un exemple d’utilisation. Le but initial étant de créer un Caption Panel à bords arrondis, dont le style du titre soit paramétrable.

public class CaptionPanel extends Composite {private VerticalPanel absolutePanel;
private DecoratorPanel titlePanel;
private DecoratorPanel bodyPanel;
private VerticalPanel verticalPanel;
private HorizontalPanel horizontalPanel;
public CaptionPanel(int width, int height, int titleWidth, int titleHeight, String title){
this(width, height, null, titleWidth, titleHeight, title, null);
}

public CaptionPanel(int width, int height, String style, int titleWidth, int titleHeight, String title, String titleStyle){
absolutePanel = new VerticalPanel();
titlePanel = new DecoratorPanel();
bodyPanel = new DecoratorPanel();
verticalPanel = new VerticalPanel();
horizontalPanel = new HorizontalPanel();
horizontalPanel.
setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
absolutePanel.
setSize(width+"px", (height + titleHeight)+"px");
if (titleStyle != null){
horizontalPanel.setStyleName(titleStyle);
titlePanel.setStyleName(titleStyle);
}
if (style != null){
bodyPanel.setStyleName(style);
}

titlePanel.setSize(titleWidth+"px", titleHeight+"px");
titlePanel.add(new Label(title));
bodyPanel.setSize(width+"px", (height-titleHeight/2)+"px");
bodyPanel.add(verticalPanel);
horizontalPanel.add(titlePanel);
absolutePanel.add(horizontalPanel);
absolutePanel.add(bodyPanel);
initWidget(absolutePanel);
}

public void addTitleStyle(String style){
horizontalPanel.setStyleName(style);
titlePanel.addStyleName(style);
}

public void addBodyStyle(String style){
bodyPanel.addStyleName(style);
}

public void addContent(Widget content){
verticalPanel.add(content);
}

public void clearContent(){
verticalPanel.clear();
}

Voici quelques exemples de rendu :

Caption Panel

Fusion de fichiers PDF

Le format de fichiers pdf est l’un des plus répandus à l’heure actuelle.

En effet, il permet de transmettre des documents en étant sûr :

  • qu’ils seront lisibles à l’arrivée (il existe des lecteurs de fichiers pdf pour la quasi totalité des plateformes existantes à l’heure actuelle)
  • que le formatage sera conservé (pas de problème de mise en page, de polices manquantes,…).%%%

Nous pouvons donc être amenés à générer ou manipuler des fichiers au format pdf au sein de nos applications, et notamment à rassembler plusieurs fichiers pdf en un seul, pour en faciliter l’impression ou l’envoi par e-mail.

Pour cela, nous utilisons la librairie iText, qui est l’une des plus répandues pour la génération et la manipulation de fichiers pdf en Java.

Par exemple, fusionner deux documents nommés « fichierEntree1.pdf » et « fichierEntree2.pdf », et les sauvegarder dans un fichier nommé « fichierSortie.pdf » est réalisé grâce au code suivant :

Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("fichierSortie.pdf"));
PdfReader pdfr = new PdfReader("fichierEntree1.pdf");
PdfReader pdfr2 = new PdfReader("fichierEntree2.pdf");
document.open();
PdfContentByte cb = writer.getDirectContent();
for (int i=1; i<=pdfr.getNumberOfPages(); i++) {
document.newPage();
cb.addTemplate(writer.getImportedPage(pdfr, i),0,0);
}
for (int i=1; i<=pdfr2.getNumberOfPages(); i++) {
document.newPage();
cb.addTemplate(writer.getImportedPage(pdfr2, i),0,0);
}
document.close();

Enquête sur l’utilisation des méthodes agiles en France

Le Scrum User Group France vient de lancer une enquête sur l’utilisation des méthodes agiles en France :

Nous avons pour ambition de faire une photographie la plus juste possible de l’adoption et de l’utilisation des méthodes agiles en France ainsi que le niveau de satisfaction des praticiens.
Pour qu’elle soit significative, nous souhaitons qu’un maximum d’entreprises utilisatrices répondent.
Pour cette raison, nous sollicitons votre aide afin d’y répondre bien entendu mais aussi par le biais de la diffusion de cette enquête à d’autres utilisateurs qui pourraient partager leur expérience en répondant au questionnaire.

L’enquête se trouve ici, la réponse ne prend pas plus de 5 minutes.

Vous pouvez désigner Karine Mazet comme marraine, elle n’a pas encore de Wii :).

Tomcat : utilisation de multi instances

Nous utilisons Tomcat comme moteur de Servlet.

L’installation d’un Tomcat standard est assez simple, mais on en atteint très vite les limites.
En effet, selon l’environnement, on va avoir besoin de plusieurs instance de Tomcat ; par exemple, pour toute la phase en amont de la pré-prod / prod, on souhaite gérer des environnements d’intégration, de recettte, de montée en charge, …

La première solution est de multiplier les installations de Tomcat. C’est très simple à mettre en place , mais lorsque l’on change de version du serveur, on doti modifier toutes les installations.

Une autre solution assez simple apportée par Tomcat, est la possibilité de définir plusieurs instances de Tomcat pour une même installation. Nous allons décrire dans ce billet comment le mettre en place :

  • La première chose à faire est de définir un scipt de démarrage/arrêt par instance de Tomcat.
    • On crée un fichier $TOMCAT_HOME/bin/startupMonInstance.sh qui sera identique au startup.sh auquel on ajoute :
    • (le chemin peut être complètement indépendant de l’arborescence Tomcat)
      On peut également modifier les paramètres de la JVM de chaque instance en ajoutant dans ce script la variable CATALINA_OPTS.
    • Et un fichier $TOMCAT_HOME/bin/shutdownMonInstance.sh qui sera identique au shutdown.sh auquel on ajoute :
  • On copie les fichiers de configuration $TOMCAT_HOME/conf/*.* dans le répertoire monInstance/conf
  • On modifie les ports du fichier monInstance/conf /server.xml pour pouvoir lancer les différents tomcats en même temps.

Au démarrage de chaque instance, Tomcat se charge de créer les répertoires manquants, notamment le webapps.

GWT et PureMVC

Utilisation de PureMVC

La mise en œuvre d’une application RIA robuste, maintenable, réutilisable et évolutive nécessite l’utilisation des modèles de conceptions éprouvés. Notre application est réalisée en GWT basée sur une architecture multi-couche. Voici quelques unes des exigences auxquelles doit répondre notre application :

  • Faible couplage entre les différentes couches,
  • Chaque composant de l’application doit avoir un rôle clair et précis,
  • Accès transparent à des services distants ou co-localisés,
  • Une mise en cache des données utilisées fréquemment afin d’accroître les performances.

Afin de répondre à ces exigences, notre choix s’est porté sur le framework PureMVC. Ce framework met en œuvre le méta Pattern MVC. Il permet de découpler vues et modèles en instaurant entre eux un protocole d’échanges basé sur le pattern Observateur. Ce modèle de conception établit un type d’interaction Diffusion / Souscription.

Le framework PureMVC permet de séparer la couche Vue de notre application en trois tiers bien distincts : le modèle, la vue et le contrôleur. Ces trois tiers sont mis en œuvre par trois classes appelées ModelView et Controller. Elles constituent les acteurs centraux du framework. Ces acteurs collaborent entre eux par le biais d’une Façade.
La classe Façade détient les références des trois acteurs centraux. Chaque acteur est couplé avec des collaborateurs. La façade initialise les acteurs centraux et procède à une phase d’enregistrement des collaborateurs :

  • Model — registerProxy (<IProxy>)
  • Vue — registerMediator (<IMediator>)
  • Controller — registerCommand(<notificationName>, <ICommand>)

Le modèle détient des références des classes Proxy. Chaque proxy communique avec des services distants et sert de cache des données fréquemment utilisées. La vue détient des références des classes Mediator. Un médiateur représente des composants visuels. Enfin le contrôleur détient des références des classes Command. Les commandes peuvent interagir directement avec des classes Proxy ou envoyer des notifications.

Voici un schéma qui illustre la manière dont sont orchestrés les échanges entre les différents acteurs du framework PureMVC :

PureMVC

L’Esprit Agile a soufflé

L’Esprit Agile a soufflé sur Marseille ce Mardi 17 Mars dans l’Amphi de l’ECM.

Ce premier évènement du genre dans la région a été une belle réussite avec un peu plus de 80 personnes présentes.
Nous remercions encore une fois tous les participants, intervenants, partenaires et bien sûr les étudiants de l’ECM avec qui nous avons organisé cette rencontre.

Equipe

Merci à Jean-Marie pour les photos

Les présentations et vidéo seront disponibles la semaine prochaine sur le site de l’Esprit Agile.

Nous espérons ne pas en rester à cet évènement ponctuel, mais fédérer des utilisateurs de méthodes agiles ou les personnes et entreprises intéressées au sein d’une association dont le but serait de favoriser les échanges et la mise en place de méthodes agiles.

Je vous invite donc à nous contacter si cette démarche vous intéresse, cela nous permettra de pousser un peu plus cette démarche.

Lire un fichier dont on ne connaît pas l’encodage

Lorsque l’on développe une application, on est souvent amené à lire des fichiers provenant de diverses sources (utilisateurs, autres programmes,…), et dont on ne connaît pas forcément le format, notamment l’encodage.

Java ne fournit pas en standard de moyen de détecter l’encodage d’un fichier, mais grâce aux nombreuses librairies externes disponibles, il est possible de résoudre ce problème.

Nous avons, pour notre part choisi d’utiliser la librairie ICU, développée par IBM, et ce pour plusieurs raisons :

  • c’est une librairie très répandue, et utilisée par de nombreux projets majeurs (gage de sa fiabilité)
  • elle est distribuée sous une licence open source non restrictive, et soutenue par IBM (gage de sa pérennité)
  • nous utilisons BIRT à l’intérieur de notre application, qui dépend lui-même d’ICU, et nous avions donc déjà cette librairie au sein de notre projet.

Voici comment nous l’utilisons dans l’application :

String fileName = "...";
final CharsetDetector detector = new CharsetDetector();
detector.setText(new BufferedInputStream (new FileInputStream(fileName)));
Reader fileReader = detector.detect().getReader();

En faisant cela, nous obtenons donc un reader classique java, qui nous permettra de lire le fichier sans se préoccuper de l’encodage, et de ne pas avoir de problème avec le traitement des caractères non ASCII.
Dans cet exemple, l’utilisation d’un BufferredInputStream est nécessaire, en effet, ICU va lire une partie du fichier pour déterminer l’encodage, puis revenir au début du fichier grâce à la méthode reset() lorsqu’on lui demande un reader, méthode que l’on ne peut pas utiliser sur un FileInputStream.

Loading...
X